Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Android/build/build/soong/sdk/   (Android Betriebssystem Version 17©)  Datei vom 26.5.2026 mit Größe 19 kB image not shown  

Quelle  testing.go   Sprache: unbekannt

 
Spracherkennung für: .go vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

// Copyright 2019 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package sdk

import (
 "fmt"
 "path/filepath"
 "strings"
 "testing"

 "android/soong/android"
 "android/soong/apex"
 "android/soong/cc"
 "android/soong/genrule"
 "android/soong/java"

 "github.com/google/blueprint/proptools"
)

// Prepare for running an sdk test with an apex.
var prepareForSdkTestWithApex = android.GroupFixturePreparers(
 apex.PrepareForTestWithApexBuildComponents,
 android.FixtureAddTextFile("sdk/tests/Android.bp", `
  apex_key {
   name: "myapex.key",
   public_key: "myapex.avbpubkey",
   private_key: "myapex.pem",
  }

  android_app_certificate {
   name: "myapex.cert",
   certificate: "myapex",
  }
 `),

 android.FixtureMergeMockFs(map[string][]byte{
  "apex_manifest.json":                           nil,
  "system/sepolicy/apex/myapex-file_contexts":    nil,
  "system/sepolicy/apex/myapex2-file_contexts":   nil,
  "system/sepolicy/apex/mysdkapex-file_contexts": nil,
  "sdk/tests/myapex.avbpubkey":                   nil,
  "sdk/tests/myapex.pem":                         nil,
  "sdk/tests/myapex.x509.pem":                    nil,
  "sdk/tests/myapex.pk8":                         nil,
 }),
)

// Legacy preparer used for running tests within the sdk package.
//
// This includes everything that was needed to run any test in the sdk package prior to the
// introduction of the test fixtures. Tests that are being converted to use fixtures directly
// rather than through the testSdkError() and testSdkWithFs() methods should avoid using this and
// instead should use the various preparers directly using android.GroupFixturePreparers(...) to
// group them when necessary.
//
// deprecated
var prepareForSdkTest = android.GroupFixturePreparers(
 cc.PrepareForTestWithCcDefaultModules,
 genrule.PrepareForTestWithGenRuleBuildComponents,
 java.PrepareForTestWithJavaBuildComponents,
 PrepareForTestWithSdkBuildComponents,

 prepareForSdkTestWithApex,

 cc.PrepareForTestOnWindows,
 android.FixtureModifyConfig(func(config android.Config) {
  // Add windows as a default disable OS to test behavior when some OS variants
  // are disabled.
  config.Targets[android.Windows] = []android.Target{
   {
    Os:           android.Windows,
    Arch:         android.Arch{ArchType: android.X86_64},
    NativeBridge: android.NativeBridgeDisabled,
    HostCross:    true,
   },
  }
 }),

 // Add a build number file.
 android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
  variables.BuildNumberFile = proptools.StringPtr(BUILD_NUMBER_FILE)
 }),

 // Make sure that every test provides all the source files.
 android.PrepareForTestDisallowNonExistentPaths,
 android.MockFS{
  "Test.java": nil,
 }.AddToFixture(),
)

var PrepareForTestWithSdkBuildComponents = android.GroupFixturePreparers(
 android.FixtureRegisterWithContext(registerModuleExportsBuildComponents),
 android.FixtureRegisterWithContext(registerSdkBuildComponents),
)

func testSdkWithFs(t *testing.T, bp string, fs android.MockFS) *android.TestResult {
 t.Helper()
 return android.GroupFixturePreparers(
  prepareForSdkTest,
  fs.AddToFixture(),
 ).RunTestWithBp(t, bp)
}

func testSdkError(t *testing.T, pattern, bp string) {
 t.Helper()
 prepareForSdkTest.
  ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(pattern)).
  RunTestWithBp(t, bp)
}

func ensureListContains(t *testing.T, result []string, expected string) {
 t.Helper()
 if !android.InList(expected, result) {
  t.Errorf("%q is not found in %v", expected, result)
 }
}

// Analyse the sdk build rules to extract information about what it is doing.
//
// e.g. find the src/dest pairs from each cp command, the various zip files
// generated, etc.
func getSdkSnapshotBuildInfo(t *testing.T, result *android.TestResult, sdk *sdk) *snapshotBuildInfo {
 info := &snapshotBuildInfo{
  t:                  t,
  r:                  result,
  androidBpContents:  sdk.GetAndroidBpContentsForTests(),
  infoContents:       sdk.GetInfoContentsForTests(),
  targetBuildRelease: sdk.builderForTests.targetBuildRelease,
 }

 buildParams := sdk.BuildParamsForTests()
 copyRules := &strings.Builder{}
 otherCopyRules := &strings.Builder{}
 snapshotDirPrefix := sdk.builderForTests.snapshotDir.String() + "/"

 seenBuildNumberFile := false
 for _, bp := range buildParams {
  switch bp.Rule.String() {
  case android.CpRule.String(), android.CpWithBash.String():
   output := bp.Output
   // Get destination relative to the snapshot root
   dest := output.Rel()
   src := android.NormalizePathForTesting(bp.Input)
   // We differentiate between copy rules for the snapshot, and copy rules for the install file.
   if strings.HasPrefix(output.String(), snapshotDirPrefix) {
    // Don't include the build-number.txt file in the copy rules as that would break lots of
    // tests, just verify that it is copied here as it should appear in every snapshot.
    if output.Base() == BUILD_NUMBER_FILE {
     seenBuildNumberFile = true
    } else {
     // Get source relative to build directory.
     _, _ = fmt.Fprintf(copyRules, "%s -> %s\n", src, dest)
    }
    info.snapshotContents = append(info.snapshotContents, dest)
   } else {
    _, _ = fmt.Fprintf(otherCopyRules, "%s -> %s\n", src, dest)
   }

  case repackageZip.String():
   // Add the destdir to the snapshot contents as that is effectively where
   // the content of the repackaged zip is copied.
   dest := bp.Args["destdir"]
   info.snapshotContents = append(info.snapshotContents, dest)

  case zipFiles.String():
   // This could be an intermediate zip file and not the actual output zip.
   // In that case this will be overridden when the rule to merge the zips
   // is processed.
   info.outputZip = android.NormalizePathForTesting(bp.Output)

  case mergeZips.String():
   // Copy the current outputZip to the intermediateZip.
   info.intermediateZip = info.outputZip
   mergeInput := android.NormalizePathForTesting(bp.Input)
   if info.intermediateZip != mergeInput {
    t.Errorf("Expected intermediate zip %s to be an input to merge zips but found %s instead",
     info.intermediateZip, mergeInput)
   }

   // Override output zip (which was actually the intermediate zip file) with the actual
   // output zip.
   info.outputZip = android.NormalizePathForTesting(bp.Output)

   // Save the zips to be merged into the intermediate zip.
   info.mergeZips = android.NormalizePathsForTesting(bp.Inputs)
  }
 }

 if !seenBuildNumberFile {
  panic(fmt.Sprintf("Every snapshot must include the %s file", BUILD_NUMBER_FILE))
 }

 info.copyRules = copyRules.String()
 info.otherCopyRules = otherCopyRules.String()

 return info
}

// The enum of different sdk snapshot tests performed by CheckSnapshot.
type snapshotTest int

const (
 // The enumeration of the different test configurations.
 // A test with the snapshot/Android.bp file but without the original Android.bp file.
 checkSnapshotWithoutSource snapshotTest = iota

 // A test with both the original source and the snapshot, with the source preferred.
 checkSnapshotWithSourcePreferred

 // A test with both the original source and the snapshot, with the snapshot preferred.
 checkSnapshotPreferredWithSource

 // The directory into which the snapshot will be 'unpacked'.
 snapshotSubDir = "snapshot"
)

// Check the snapshot build rules.
//
// Takes a list of functions which check different facets of the snapshot build rules.
// Allows each test to customize what is checked without duplicating lots of code
// or proliferating check methods of different flavors.
func CheckSnapshot(t *testing.T, result *android.TestResult, name string, dir string, checkers ...snapshotBuildInfoChecker) {
 t.Helper()

 // The sdk CommonOS variant is always responsible for generating the snapshot.
 variant := android.CommonOS.Name

 sdk := result.Module(name, variant).(*sdk)

 snapshotBuildInfo := getSdkSnapshotBuildInfo(t, result, sdk)

 // Check state of the snapshot build.
 for _, checker := range checkers {
  checker(snapshotBuildInfo)
 }

 // Make sure that the generated zip file is in the correct place.
 actual := snapshotBuildInfo.outputZip
 if dir != "" {
  dir = filepath.Clean(dir) + "/"
 }
 suffix := "-" + soongSdkSnapshotVersionCurrent

 expectedZipPath := fmt.Sprintf(".intermediates/%s%s/%s/%s%s.zip", dir, name, variant, name, suffix)
 android.AssertStringEquals(t, "Snapshot zip file in wrong place", expectedZipPath, actual)

 // Populate a mock filesystem with the files that would have been copied by
 // the rules.
 fs := android.MockFS{}
 for _, dest := range snapshotBuildInfo.snapshotContents {
  fs[filepath.Join(snapshotSubDir, dest)] = nil
 }
 fs[filepath.Join(snapshotSubDir, "Android.bp")] = []byte(snapshotBuildInfo.androidBpContents)

 // If the generated snapshot builders not for the current release then it cannot be loaded by
 // the current release.
 if snapshotBuildInfo.targetBuildRelease != buildReleaseCurrent {
  return
 }

 // The preparers from the original source fixture.
 sourcePreparers := result.Preparer()

 // Preparer to combine the snapshot and the source.
 snapshotPreparer := android.GroupFixturePreparers(sourcePreparers, fs.AddToFixture())

 var runSnapshotTestWithCheckers = func(t *testing.T, testConfig snapshotTest, extraPreparer android.FixturePreparer) {
  t.Helper()
  customization := snapshotBuildInfo.snapshotTestCustomization(testConfig)
  customizedPreparers := android.GroupFixturePreparers(customization.preparers...)

  // TODO(b/183184375): Set Config.TestAllowNonExistentPaths = false to verify that all the
  //  files the snapshot needs are actually copied into the snapshot.

  // Run the snapshot with the snapshot preparer and the extra preparer, which must come after as
  // it may need to modify parts of the MockFS populated by the snapshot preparer.
  result := android.GroupFixturePreparers(snapshotPreparer, customizedPreparers, extraPreparer).
   ExtendWithErrorHandler(customization.errorHandler).
   RunTest(t)

  // Perform any additional checks the test need on the result of processing the snapshot.
  for _, checker := range customization.checkers {
   checker(t, result)
  }
 }

 t.Run("snapshot without source", func(t *testing.T) {
  t.Parallel()
  // Remove the source Android.bp file to make sure it works without.
  removeSourceAndroidBp := android.FixtureModifyMockFS(func(fs android.MockFS) {
   delete(fs, "Android.bp")
  })

  runSnapshotTestWithCheckers(t, checkSnapshotWithoutSource, removeSourceAndroidBp)
 })

 t.Run("snapshot with source preferred", func(t *testing.T) {
  t.Parallel()
  runSnapshotTestWithCheckers(t, checkSnapshotWithSourcePreferred, android.NullFixturePreparer)
 })

 t.Run("snapshot preferred with source", func(t *testing.T) {
  t.Parallel()
  // Replace the snapshot/Android.bp file with one where "prefer: false," has been replaced with
  // "prefer: true,"
  preferPrebuilts := android.FixtureModifyMockFS(func(fs android.MockFS) {
   snapshotBpFile := filepath.Join(snapshotSubDir, "Android.bp")
   unpreferred := string(fs[snapshotBpFile])
   fs[snapshotBpFile] = []byte(strings.ReplaceAll(unpreferred, "prefer: false,", "prefer: true,"))

   prebuiltApexBpFile := "prebuilts/apex/Android.bp"
   if prebuiltApexBp, ok := fs[prebuiltApexBpFile]; ok {
    fs[prebuiltApexBpFile] = []byte(strings.ReplaceAll(string(prebuiltApexBp), "prefer: false,", "prefer: true,"))
   }
  })

  runSnapshotTestWithCheckers(t, checkSnapshotPreferredWithSource, preferPrebuilts)
 })
}

type snapshotBuildInfoChecker func(info *snapshotBuildInfo)

// Check that the snapshot's generated Android.bp is correct.
//
// Both the expected and actual string are both trimmed before comparing.
func checkAndroidBpContents(expected string) snapshotBuildInfoChecker {
 return func(info *snapshotBuildInfo) {
  info.t.Helper()
  android.AssertTrimmedStringEquals(info.t, "Android.bp contents do not match", expected, info.androidBpContents)
 }
}

func checkAndroidBpDoesContain(expected string) snapshotBuildInfoChecker {
 return func(info *snapshotBuildInfo) {
  info.t.Helper()
  android.AssertStringDoesContain(info.t, "Android.bp contents do not match", info.androidBpContents, expected)
 }
}

func checkAndroidBpDoesNotContain(unexpected string) snapshotBuildInfoChecker {
 return func(info *snapshotBuildInfo) {
  info.t.Helper()
  android.AssertStringDoesNotContain(info.t, "Android.bp contents do not match", info.androidBpContents, unexpected)
 }
}

// Check that the snapshot's copy rules are correct.
//
// The copy rules are formatted as <src> -> <dest>, one per line and then compared
// to the supplied expected string. Both the expected and actual string are trimmed
// before comparing.
func checkAllCopyRules(expected string) snapshotBuildInfoChecker {
 return func(info *snapshotBuildInfo) {
  info.t.Helper()
  android.AssertTrimmedStringEquals(info.t, "Incorrect copy rules", expected, info.copyRules)
 }
}

func checkAllOtherCopyRules(expected string) snapshotBuildInfoChecker {
 return func(info *snapshotBuildInfo) {
  info.t.Helper()
  android.AssertTrimmedStringEquals(info.t, "Incorrect copy rules", expected, info.otherCopyRules)
 }
}

// Check that the specified paths match the list of zips to merge with the intermediate zip.
func checkMergeZips(expected ...string) snapshotBuildInfoChecker {
 return func(info *snapshotBuildInfo) {
  info.t.Helper()
  if info.intermediateZip == "" {
   info.t.Errorf("No intermediate zip file was created")
  }

  android.AssertDeepEquals(info.t, "mismatching merge zip files", expected, info.mergeZips)
 }
}

// Check that the snapshot's info contents are ciorrect.
//
// Both the expected and actual string are both trimmed before comparing.
func checkInfoContents(config android.Config, expected string) snapshotBuildInfoChecker {
 return func(info *snapshotBuildInfo) {
  info.t.Helper()
  android.AssertTrimmedStringEquals(info.t, "info contents do not match",
   expected, android.StringRelativeToTop(config, info.infoContents))
 }
}

type resultChecker func(t *testing.T, result *android.TestResult)

// snapshotTestPreparer registers a preparer that will be used to customize the specified
// snapshotTest.
func snapshotTestPreparer(snapshotTest snapshotTest, preparer android.FixturePreparer) snapshotBuildInfoChecker {
 return func(info *snapshotBuildInfo) {
  customization := info.snapshotTestCustomization(snapshotTest)
  customization.preparers = append(customization.preparers, preparer)
 }
}

// snapshotTestChecker registers a checker that will be run against the result of processing the
// generated snapshot for the specified snapshotTest.
func snapshotTestChecker(snapshotTest snapshotTest, checker resultChecker) snapshotBuildInfoChecker {
 return func(info *snapshotBuildInfo) {
  customization := info.snapshotTestCustomization(snapshotTest)
  customization.checkers = append(customization.checkers, checker)
 }
}

// snapshotTestErrorHandler registers an error handler to use when processing the snapshot
// in the specific test case.
//
// Generally, the snapshot should work with all the test cases but some do not and just in case
// there are a lot of issues to resolve, or it will take a lot of time this is a
// get-out-of-jail-free card that allows progress to be made.
//
// deprecated: should only be used as a temporary workaround with an attached to do and bug.
func snapshotTestErrorHandler(snapshotTest snapshotTest, handler android.FixtureErrorHandler) snapshotBuildInfoChecker {
 return func(info *snapshotBuildInfo) {
  customization := info.snapshotTestCustomization(snapshotTest)
  customization.errorHandler = handler
 }
}

// Encapsulates information provided by each test to customize a specific snapshotTest.
type snapshotTestCustomization struct {
 // Preparers that are used to customize the test fixture before running the test.
 preparers []android.FixturePreparer

 // Checkers that are run on the result of processing the preferred snapshot in a specific test
 // case.
 checkers []resultChecker

 // Specify an error handler for when processing a specific test case.
 //
 // In some cases the generated snapshot cannot be used in a test configuration. Those cases are
 // invariably bugs that need to be resolved but sometimes that can take a while. This provides a
 // mechanism to temporarily ignore that error.
 errorHandler android.FixtureErrorHandler
}

// Encapsulates information about the snapshot build structure in order to insulate tests from
// knowing too much about internal structures.
//
// All source/input paths are relative either the build directory. All dest/output paths are
// relative to the snapshot root directory.
type snapshotBuildInfo struct {
 t *testing.T

 // The result from RunTest()
 r *android.TestResult

 // The contents of the generated Android.bp file
 androidBpContents string

 // The contents of the info file.
 infoContents string

 // The paths, relative to the snapshot root, of all files and directories copied into the
 // snapshot.
 snapshotContents []string

 // A formatted representation of the src/dest pairs for a snapshot, one pair per line,
 // of the format src -> dest
 copyRules string

 // A formatted representation of the src/dest pairs for files not in a snapshot, one pair
 // per line, of the format src -> dest
 otherCopyRules string

 // The path to the intermediate zip, which is a zip created from the source files copied
 // into the snapshot directory and which will be merged with other zips to form the final output.
 // Is am empty string if there is no intermediate zip because there are no zips to merge in.
 intermediateZip string

 // The paths to the zips to merge into the output zip, does not include the intermediate
 // zip.
 mergeZips []string

 // The final output zip.
 outputZip string

 // The target build release.
 targetBuildRelease *buildRelease

 // The test specific customizations for each snapshot test.
 snapshotTestCustomizations snapshotTestCustomizationSet
}

type snapshotTestCustomizationSet struct {
 snapshotWithoutSource       *snapshotTestCustomization
 snapshotWithSourcePreferred *snapshotTestCustomization
 snapshotPreferredWithSource *snapshotTestCustomization
}

func (s *snapshotTestCustomizationSet) customization(snapshotTest snapshotTest) **snapshotTestCustomization {
 var customization **snapshotTestCustomization
 switch snapshotTest {
 case checkSnapshotWithoutSource:

  customization = &s.snapshotWithoutSource
 case checkSnapshotWithSourcePreferred:
  customization = &s.snapshotWithSourcePreferred
 case checkSnapshotPreferredWithSource:
  customization = &s.snapshotPreferredWithSource
 default:
  panic(fmt.Errorf("unsupported snapshotTest %v", snapshotTest))
 }
 return customization
}

// snapshotTestCustomization gets the test specific customization for the specified snapshotTest.
//
// If no customization was created previously then it creates a default customization.
func (i *snapshotBuildInfo) snapshotTestCustomization(snapshotTest snapshotTest) *snapshotTestCustomization {
 customization := i.snapshotTestCustomizations.customization(snapshotTest)
 if *customization == nil {
  *customization = &snapshotTestCustomization{
   errorHandler: android.FixtureExpectsNoErrors,
  }
 }
 return *customization
}

[Dauer der Verarbeitung: 0.24 Sekunden, vorverarbeitet 2026-06-28]