Migrate test components

To migrate your test components, follow these steps:

  1. Migrate the test manifest
  2. Update test dependencies
  3. Migrate component features
  4. Verify the migrated tests

Migrate the test manifest

Find the GN build rules for the tests that exercise your component. Typically this is a fuchsia_test_package() or fuchsia_unittest_package().

Unit test packages

The preferred practice for tests declared with a fuchsia_unittest_package() build rule is to use the generated manifest provided by the Fuchsia build system.

To allow the GN target to generate your manifest, remove the manifest attribute from the fuchsia_unittest_package():

fuchsia_unittest_package("my_component_tests") {
  {{ '<strike>' }}manifest = "meta/my_component_test.cmx"{{ '</strike>' }}
  deps = [ ":my_component_test" ]
}

Your test package is now able to execute using Components v2 and the Test Runner Framework.

Test packages

Consider the following example test component manifest:

// my_component_test.cmx
{
    "include": [
        "syslog/client.shard.cmx"
    ],
    "program": {
        "binary": "bin/my_component_test"
    }
}

To migrate this test to the Test Runner Framework, do the following:

  1. Create a CML file that points to the test binary that includes the appropriate test runner:

    Note: See the available test runners provided by the framework.

    // my_component_test.cml
    {
        include: [
            // Select the appropriate test runner shard here:
            // rust, gtest, go, etc.
            "//src/sys/test_runners/rust/default.shard.cml",
            // Enable system logging
            "syslog/client.shard.cml",
        ],
        program: {
            binary: "bin/my_component_test",
        }
    }
    
  2. Locate the GN build rule for your test component referenced by the fuchsia_test_package():

    fuchsia_component("my_component_test") {
      testonly = true
      manifest = "meta/my_component_test.cmx"
      deps = [ ":bin_test" ]
    }
    
    fuchsia_test_package("my_component_tests") {
      deps = [ ":my_component_test" ]
    }
    
  3. Update your test component's build rule to reference the new CML file:

    fuchsia_component("my_component_test") {
      testonly = true
      {{ '<strong>' }}manifest = "meta/my_component_test.cml"{{ '</strong>' }}
      deps = [ ":bin_test" ]
    }
    
    fuchsia_test_package("my_component_tests") {
      deps = [ ":my_component_test" ]
    }
    

Update test dependencies

A test may include or depend on components that are separate from the test component. Here are some things to look for:

  • Does your test have a CMX with fuchsia.test facets, such as injected-services or system-services?
  • Does your test create environments in-process? If so, does it create a separate environment for each test case?

Note: The Test Runner Framework executes tests within a realm that enforces hermetic component resolution, which means that test components must resolve dependencies from within their own package. For more details, see hermetic component resolution.

The migration procedure varies depending on the testing framework features in your v1 component:

Note: For more details on the services and capabilities provided to components by the Test Runner Framework, see the test manager documentation.

System service dependencies

For tests that use system-services test facets, consider if they can be converted to injected services instead. Injecting services is the preferred method because it promotes hermetic test behavior.

For certain non-hermetic tests, the Test Runner Framework provides the test realm with the following services:

ServiceDescription
fuchsia.scheduler.ProfileProviderProfile provider for scheduler
fuchsia.sysmem.AllocatorAllocates system memory buffers
fuchsia.tracing.provider.RegistryRegister to trace provider
fuchsia.vulkan.loader.LoaderVulkan library provider
fuchsia.sys.LoaderCFv1 loader service to help with
: : migration. :
fuchsia.sys.EnvironmentCFv1 environment service to help with
: : migration. :

Consider the following example test component that uses a single system service, fuchsia.sysmem.Allocator:

// my_component_test.cmx
{
    "facets": {
        "fuchsia.test": {
            "system-services": [
                "fuchsia.sysmem.Allocator"
            ]
        }
    },
    "program": {
        "binary": "bin/my_component_test"
    },
    "sandbox": {
        "services": [
            "fuchsia.sysmem.Allocator"
        ]
    }
}

To migrate this test to the Test Runner Framework, declare each available system service with the other required services in your test component manifest. Since this test uses the fuchsia.sysmem.Allocator system capability, it also needs to be marked as hermetic: "false" as shown below.

// my_component_test.cml

{
    include: [
        // Select the appropriate test runner shard here:
        // rust, gtest, go, etc.
        "//src/sys/test_runners/rust/default.shard.cml",
    ],
    program: {
        binary: "bin/my_component_test",
    },
    {{ '<strong>' }}facets: {
        "fuchsia.test": {
            type: "system"
        },
    },
    use: [
        {
            protocol: [ "fuchsia.sysmem.Allocator" ],
        },
    ],{{ '</strong>' }}
}

Injected service dependencies

For tests that use other fuchsia.test facets, such as injected-services, your test component manifest must declare each dependent component and route the provided capabilities to the test component.

In the following example, suppose there's a single injected service, fuchsia.pkg.FontResolver:

// my_component_test.cmx
{
    "facets": {
        "fuchsia.test": {
            "injected-services": {
                "fuchsia.pkg.FontResolver":
                    "fuchsia-pkg://fuchsia.com/font_provider_test#meta/mock_font_resolver.cmx"
            }
        }
    },
    "program": {
        "binary": "bin/my_component_test"
    },
    "sandbox": {
        "services": [
            "fuchsia.pkg.FontResolver"
        ]
    }
}

To migrate this test to the Test Runner Framework, do the following:

  1. Create a CML file for the test component that points to the test binary and includes the appropriate test runner:

    Note: See test runners that are provided by the framework.

    // my_component_test.cml (test component)
    {
        include: [
            // Select the appropriate test runner shard here:
            // rust, gtest, go, etc.
            "//src/sys/test_runners/rust/default.shard.cml",
        ],
        program: {
            // Binary containing tests
            binary: "bin/font_provider_test",
        },
        use: [
            ...
        ],
    }
    
  2. You need CML files for each component that provides a capability needed in the test. If there is an existing CML file for the component providing the injected service, you may be able to reuse it. Otherwise if the mock component is being ported to v2, create a new CML file. If the mock component has not been ported to v2 yet, wrap the component using cmx_runner.

    • {CML component}

      // mock_font_resolver.cml (capability provider)
      {
          program: {
          runner: "elf",
          binary: "bin/mock_font_resolver",
          },
          use: [
              //  mock_font_resolver's dependencies.
              {
                  protocol: [ "fuchsia.proto.SomeProtocol" ],
              },
          ],
          capabilities: [
              {
                  protocol: [ "fuchsia.pkg.FontResolver" ],
              },
          ],
          expose: [
              {
                  protocol: "fuchsia.pkg.FontResolver",
                  from: "self",
              },
          ],
      }
      
    • {Wrapped CMX component}

      // mock_font_resolver.cml (capability provider)
      {
          include: [
              // Use `cmx_runner` to wrap the component.
              "//src/sys/test_manager/cmx_runner/default.shard.cml",
              "syslog/client.shard.cml",
          ],
          program: {
              // wrap v1 component
              legacy_url: "fuchsia-pkg://fuchsia.com/font_provider_test#meta/mock_font_resolver.cmx",
          },
          use: [
              // if `mock_font_resolver.cmx` depends on some other protocol.
              {
                  protocol: [ "fuchsia.proto.SomeProtocol" ],
              },
              // Note: Wrapped legacy component can only use protocol capabilities.
          ],
          // expose capability provided by mock component.
          capabilities: [
              {
                  protocol: [ "fuchsia.pkg.FontResolver" ],
              },
          ],
          expose: [
              {
                  protocol: "fuchsia.pkg.FontResolver",
                  from: "self",
              },
          ],
      }
      

    Note: The CML files for the capability providers can be distributed in the same package that contained the v1 test. Follow the same instructions in Migrate the component manifest that you used to package your component.

  3. Add the capability provider(s) as children of the test component, and route the capabilities from each provider.

    // my_component_test.cml (test component)
    {
        ...
    
        // Add capability providers
        children: [
            {
                name: "font_resolver",
                url: "#meta/mock_font_resolver.cm",
            },
        ],
        // Route capabilities to the test
        use: [
            {
                protocol: [ "fuchsia.pkg.FontResolver" ],
                from: "#font_resolver",
            },
        ],
        offer: [
            {
                // offer dependencies to mock font provider.
                protocol: [ "fuchsia.proto.SomeProtocol" ],
                from: "#some_other_child",
            },
        ],
    }
    
  4. Package the test component and capability provider(s) together into a single hermetic fuchsia_test_package():

    • {CML component}

      # Test component
      fuchsia_component("my_component_test") {
      testonly = true
      manifest = "meta/my_component_test.cml"
      deps = [ ":bin_test" ]
      }
      
      fuchsia_component("mock_font_resolver") {
      testonly = true
      manifest = "meta/mock_font_resolver.cml"
      deps = [ ":mock_font_resolver_bin" ]
      }
      
      # Hermetic test package
      fuchsia_test_package("my_component_tests") {
      test_components = [ ":my_component_test" ]
      deps = [ ":mock_font_resolver" ]
      }
      
    • {Wrapped CMX component}

      # Test component
      fuchsia_component("my_component_test") {
      testonly = true
      manifest = "meta/my_component_test.cml"
      deps = [ ":bin_test" ]
      }
      
      fuchsia_component("mock_font_resolver") {
      testonly = true
      manifest = "meta/mock_font_resolver.cml"
      deps = [ {{ '<var label="legacy_component">"//path/to/legacy(v1)_component"</var>' }} ]
      }
      
      # Hermetic test package
      fuchsia_test_package("my_component_tests") {
      test_components = [ ":my_component_test" ]
      deps = [ ":mock_font_resolver" ]
      }
      

For more details on providing external capabilities to tests, see Integration testing topologies.

Migrate component features

Explore the following sections for additional migration guidance on specific features your test components may support:

Verify the migrated tests

Build and run your test and verify that it passes:

fx build && fx test my_component_tests

If your test doesn‘t run correctly or doesn’t start at all, try following the advice in Troubleshooting components.