fixture.go 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050
  1. // Copyright 2021 Google Inc. All rights reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package android
  15. import (
  16. "fmt"
  17. "runtime"
  18. "strings"
  19. "testing"
  20. )
  21. // Provides support for creating test fixtures on which tests can be run. Reduces duplication
  22. // of test setup by allow tests to easily reuse setup code.
  23. //
  24. // Fixture
  25. // =======
  26. // These determine the environment within which a test can be run. Fixtures are mutable and are
  27. // created and mutated by FixturePreparer instances. They are created by first creating a base
  28. // Fixture (which is essentially empty) and then applying FixturePreparer instances to it to modify
  29. // the environment.
  30. //
  31. // FixturePreparer
  32. // ===============
  33. // These are responsible for modifying a Fixture in preparation for it to run a test. Preparers are
  34. // intended to be immutable and able to prepare multiple Fixture objects simultaneously without
  35. // them sharing any data.
  36. //
  37. // They provide the basic capabilities for running tests too.
  38. //
  39. // FixturePreparers are only ever applied once per test fixture. Prior to application the list of
  40. // FixturePreparers are flattened and deduped while preserving the order they first appear in the
  41. // list. This makes it easy to reuse, group and combine FixturePreparers together.
  42. //
  43. // Each small self contained piece of test setup should be their own FixturePreparer. e.g.
  44. // * A group of related modules.
  45. // * A group of related mutators.
  46. // * A combination of both.
  47. // * Configuration.
  48. //
  49. // They should not overlap, e.g. the same module type should not be registered by different
  50. // FixturePreparers as using them both would cause a build error. In that case the preparer should
  51. // be split into separate parts and combined together using FixturePreparers(...).
  52. //
  53. // e.g. attempting to use AllPreparers in preparing a Fixture would break as it would attempt to
  54. // register module bar twice:
  55. // var Preparer1 = FixtureRegisterWithContext(RegisterModuleFooAndBar)
  56. // var Preparer2 = FixtureRegisterWithContext(RegisterModuleBarAndBaz)
  57. // var AllPreparers = GroupFixturePreparers(Preparer1, Preparer2)
  58. //
  59. // However, when restructured like this it would work fine:
  60. // var PreparerFoo = FixtureRegisterWithContext(RegisterModuleFoo)
  61. // var PreparerBar = FixtureRegisterWithContext(RegisterModuleBar)
  62. // var PreparerBaz = FixtureRegisterWithContext(RegisterModuleBaz)
  63. // var Preparer1 = GroupFixturePreparers(RegisterModuleFoo, RegisterModuleBar)
  64. // var Preparer2 = GroupFixturePreparers(RegisterModuleBar, RegisterModuleBaz)
  65. // var AllPreparers = GroupFixturePreparers(Preparer1, Preparer2)
  66. //
  67. // As after deduping and flattening AllPreparers would result in the following preparers being
  68. // applied:
  69. // 1. PreparerFoo
  70. // 2. PreparerBar
  71. // 3. PreparerBaz
  72. //
  73. // Preparers can be used for both integration and unit tests.
  74. //
  75. // Integration tests typically use all the module types, mutators and singletons that are available
  76. // for that package to try and replicate the behavior of the runtime build as closely as possible.
  77. // However, that realism comes at a cost of increased fragility (as they can be broken by changes in
  78. // many different parts of the build) and also increased runtime, especially if they use lots of
  79. // singletons and mutators.
  80. //
  81. // Unit tests on the other hand try and minimize the amount of code being tested which makes them
  82. // less susceptible to changes elsewhere in the build and quick to run but at a cost of potentially
  83. // not testing realistic scenarios.
  84. //
  85. // Supporting unit tests effectively require that preparers are available at the lowest granularity
  86. // possible. Supporting integration tests effectively require that the preparers are organized into
  87. // groups that provide all the functionality available.
  88. //
  89. // At least in terms of tests that check the behavior of build components via processing
  90. // `Android.bp` there is no clear separation between a unit test and an integration test. Instead
  91. // they vary from one end that tests a single module (e.g. filegroup) to the other end that tests a
  92. // whole system of modules, mutators and singletons (e.g. apex + hiddenapi).
  93. //
  94. // TestResult
  95. // ==========
  96. // These are created by running tests in a Fixture and provide access to the Config and TestContext
  97. // in which the tests were run.
  98. //
  99. // Example
  100. // =======
  101. //
  102. // An exported preparer for use by other packages that need to use java modules.
  103. //
  104. // package java
  105. // var PrepareForIntegrationTestWithJava = GroupFixturePreparers(
  106. // android.PrepareForIntegrationTestWithAndroid,
  107. // FixtureRegisterWithContext(RegisterAGroupOfRelatedModulesMutatorsAndSingletons),
  108. // FixtureRegisterWithContext(RegisterAnotherGroupOfRelatedModulesMutatorsAndSingletons),
  109. // ...
  110. // )
  111. //
  112. // Some files to use in tests in the java package.
  113. //
  114. // var javaMockFS = android.MockFS{
  115. // "api/current.txt": nil,
  116. // "api/removed.txt": nil,
  117. // ...
  118. // }
  119. //
  120. // A package private preparer for use for testing java within the java package.
  121. //
  122. // var prepareForJavaTest = android.GroupFixturePreparers(
  123. // PrepareForIntegrationTestWithJava,
  124. // FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
  125. // ctx.RegisterModuleType("test_module", testModule)
  126. // }),
  127. // javaMockFS.AddToFixture(),
  128. // ...
  129. // }
  130. //
  131. // func TestJavaStuff(t *testing.T) {
  132. // result := android.GroupFixturePreparers(
  133. // prepareForJavaTest,
  134. // android.FixtureWithRootAndroidBp(`java_library {....}`),
  135. // android.MockFS{...}.AddToFixture(),
  136. // ).RunTest(t)
  137. // ... test result ...
  138. // }
  139. //
  140. // package cc
  141. // var PrepareForTestWithCC = android.GroupFixturePreparers(
  142. // android.PrepareForArchMutator,
  143. // android.prepareForPrebuilts,
  144. // FixtureRegisterWithContext(RegisterRequiredBuildComponentsForTest),
  145. // ...
  146. // )
  147. //
  148. // package apex
  149. //
  150. // var PrepareForApex = GroupFixturePreparers(
  151. // ...
  152. // )
  153. //
  154. // Use modules and mutators from java, cc and apex. Any duplicate preparers (like
  155. // android.PrepareForArchMutator) will be automatically deduped.
  156. //
  157. // var prepareForApexTest = android.GroupFixturePreparers(
  158. // PrepareForJava,
  159. // PrepareForCC,
  160. // PrepareForApex,
  161. // )
  162. //
  163. // A set of mock files to add to the mock file system.
  164. type MockFS map[string][]byte
  165. // Merge adds the extra entries from the supplied map to this one.
  166. //
  167. // Fails if the supplied map files with the same paths are present in both of them.
  168. func (fs MockFS) Merge(extra map[string][]byte) {
  169. for p, c := range extra {
  170. validateFixtureMockFSPath(p)
  171. if _, ok := fs[p]; ok {
  172. panic(fmt.Errorf("attempted to add file %s to the mock filesystem but it already exists", p))
  173. }
  174. fs[p] = c
  175. }
  176. }
  177. // Ensure that tests cannot add paths into the mock file system which would not be allowed in the
  178. // runtime, e.g. absolute paths, paths relative to the 'out/' directory.
  179. func validateFixtureMockFSPath(path string) {
  180. // This uses validateSafePath rather than validatePath because the latter prevents adding files
  181. // that include a $ but there are tests that allow files with a $ to be used, albeit only by
  182. // globbing.
  183. validatedPath, err := validateSafePath(path)
  184. if err != nil {
  185. panic(err)
  186. }
  187. // Make sure that the path is canonical.
  188. if validatedPath != path {
  189. panic(fmt.Errorf("path %q is not a canonical path, use %q instead", path, validatedPath))
  190. }
  191. if path == "out" || strings.HasPrefix(path, "out/") {
  192. panic(fmt.Errorf("cannot add output path %q to the mock file system", path))
  193. }
  194. }
  195. func (fs MockFS) AddToFixture() FixturePreparer {
  196. return FixtureMergeMockFs(fs)
  197. }
  198. // FixtureCustomPreparer allows for the modification of any aspect of the fixture.
  199. //
  200. // This should only be used if one of the other more specific preparers are not suitable.
  201. func FixtureCustomPreparer(mutator func(fixture Fixture)) FixturePreparer {
  202. return newSimpleFixturePreparer(func(f *fixture) {
  203. mutator(f)
  204. })
  205. }
  206. // FixtureTestRunner determines the type of test to run.
  207. //
  208. // If no custom FixtureTestRunner is provided (using the FixtureSetTestRunner) then the default test
  209. // runner will run a standard Soong test that corresponds to what happens when Soong is run on the
  210. // command line.
  211. type FixtureTestRunner interface {
  212. // FinalPreparer is a function that is run immediately before parsing the blueprint files. It is
  213. // intended to perform the initialization needed by PostParseProcessor.
  214. //
  215. // It returns a CustomTestResult that is passed into PostParseProcessor and returned from
  216. // FixturePreparer.RunTestWithCustomResult. If it needs to return some custom data then it must
  217. // provide its own implementation of CustomTestResult and return an instance of that. Otherwise,
  218. // it can just return the supplied *TestResult.
  219. FinalPreparer(result *TestResult) CustomTestResult
  220. // PostParseProcessor is called after successfully parsing the blueprint files and can do further
  221. // work on the result of parsing the files.
  222. //
  223. // Successfully parsing simply means that no errors were encountered when parsing the blueprint
  224. // files.
  225. //
  226. // This must collate any information useful for testing, e.g. errs, ninja deps and custom data in
  227. // the supplied result.
  228. PostParseProcessor(result CustomTestResult)
  229. }
  230. // FixtureSetTestRunner sets the FixtureTestRunner in the fixture.
  231. //
  232. // It is an error if more than one of these is applied to a single fixture. If none of these are
  233. // applied then the fixture will use the defaultTestRunner which will run the test as if it was
  234. // being run in `m <target>`.
  235. func FixtureSetTestRunner(testRunner FixtureTestRunner) FixturePreparer {
  236. return newSimpleFixturePreparer(func(fixture *fixture) {
  237. if fixture.testRunner != nil {
  238. panic("fixture test runner has already been set")
  239. }
  240. fixture.testRunner = testRunner
  241. })
  242. }
  243. // Modify the config
  244. func FixtureModifyConfig(mutator func(config Config)) FixturePreparer {
  245. return newSimpleFixturePreparer(func(f *fixture) {
  246. mutator(f.config)
  247. })
  248. }
  249. // Modify the config and context
  250. func FixtureModifyConfigAndContext(mutator func(config Config, ctx *TestContext)) FixturePreparer {
  251. return newSimpleFixturePreparer(func(f *fixture) {
  252. mutator(f.config, f.ctx)
  253. })
  254. }
  255. // Modify the context
  256. func FixtureModifyContext(mutator func(ctx *TestContext)) FixturePreparer {
  257. return newSimpleFixturePreparer(func(f *fixture) {
  258. mutator(f.ctx)
  259. })
  260. }
  261. func FixtureRegisterWithContext(registeringFunc func(ctx RegistrationContext)) FixturePreparer {
  262. return FixtureModifyContext(func(ctx *TestContext) { registeringFunc(ctx) })
  263. }
  264. // Modify the mock filesystem
  265. func FixtureModifyMockFS(mutator func(fs MockFS)) FixturePreparer {
  266. return newSimpleFixturePreparer(func(f *fixture) {
  267. mutator(f.mockFS)
  268. // Make sure that invalid paths were not added to the mock filesystem.
  269. for p, _ := range f.mockFS {
  270. validateFixtureMockFSPath(p)
  271. }
  272. })
  273. }
  274. // Merge the supplied file system into the mock filesystem.
  275. //
  276. // Paths that already exist in the mock file system are overridden.
  277. func FixtureMergeMockFs(mockFS MockFS) FixturePreparer {
  278. return FixtureModifyMockFS(func(fs MockFS) {
  279. fs.Merge(mockFS)
  280. })
  281. }
  282. // Add a file to the mock filesystem
  283. //
  284. // Fail if the filesystem already contains a file with that path, use FixtureOverrideFile instead.
  285. func FixtureAddFile(path string, contents []byte) FixturePreparer {
  286. return FixtureModifyMockFS(func(fs MockFS) {
  287. validateFixtureMockFSPath(path)
  288. if _, ok := fs[path]; ok {
  289. panic(fmt.Errorf("attempted to add file %s to the mock filesystem but it already exists, use FixtureOverride*File instead", path))
  290. }
  291. fs[path] = contents
  292. })
  293. }
  294. // Add a text file to the mock filesystem
  295. //
  296. // Fail if the filesystem already contains a file with that path.
  297. func FixtureAddTextFile(path string, contents string) FixturePreparer {
  298. return FixtureAddFile(path, []byte(contents))
  299. }
  300. // Override a file in the mock filesystem
  301. //
  302. // If the file does not exist this behaves as FixtureAddFile.
  303. func FixtureOverrideFile(path string, contents []byte) FixturePreparer {
  304. return FixtureModifyMockFS(func(fs MockFS) {
  305. fs[path] = contents
  306. })
  307. }
  308. // Override a text file in the mock filesystem
  309. //
  310. // If the file does not exist this behaves as FixtureAddTextFile.
  311. func FixtureOverrideTextFile(path string, contents string) FixturePreparer {
  312. return FixtureOverrideFile(path, []byte(contents))
  313. }
  314. // Add the root Android.bp file with the supplied contents.
  315. func FixtureWithRootAndroidBp(contents string) FixturePreparer {
  316. return FixtureAddTextFile("Android.bp", contents)
  317. }
  318. // Merge some environment variables into the fixture.
  319. func FixtureMergeEnv(env map[string]string) FixturePreparer {
  320. return FixtureModifyConfig(func(config Config) {
  321. for k, v := range env {
  322. if k == "PATH" {
  323. panic("Cannot set PATH environment variable")
  324. }
  325. config.env[k] = v
  326. }
  327. })
  328. }
  329. // Modify the env.
  330. //
  331. // Will panic if the mutator changes the PATH environment variable.
  332. func FixtureModifyEnv(mutator func(env map[string]string)) FixturePreparer {
  333. return FixtureModifyConfig(func(config Config) {
  334. oldPath := config.env["PATH"]
  335. mutator(config.env)
  336. newPath := config.env["PATH"]
  337. if newPath != oldPath {
  338. panic(fmt.Errorf("Cannot change PATH environment variable from %q to %q", oldPath, newPath))
  339. }
  340. })
  341. }
  342. // Allow access to the product variables when preparing the fixture.
  343. type FixtureProductVariables struct {
  344. *productVariables
  345. }
  346. // Modify product variables.
  347. func FixtureModifyProductVariables(mutator func(variables FixtureProductVariables)) FixturePreparer {
  348. return FixtureModifyConfig(func(config Config) {
  349. productVariables := FixtureProductVariables{&config.productVariables}
  350. mutator(productVariables)
  351. })
  352. }
  353. var PrepareForSkipTestOnMac = newSimpleFixturePreparer(func(fixture *fixture) {
  354. if runtime.GOOS != "linux" {
  355. fixture.t.Skip("Test is only supported on linux.")
  356. }
  357. })
  358. // PrepareForDebug_DO_NOT_SUBMIT puts the fixture into debug which will cause it to output its
  359. // state before running the test.
  360. //
  361. // This must only be added temporarily to a test for local debugging and must be removed from the
  362. // test before submitting.
  363. var PrepareForDebug_DO_NOT_SUBMIT = newSimpleFixturePreparer(func(fixture *fixture) {
  364. fixture.debug = true
  365. })
  366. // GroupFixturePreparers creates a composite FixturePreparer that is equivalent to applying each of
  367. // the supplied FixturePreparer instances in order.
  368. //
  369. // Before preparing the fixture the list of preparers is flattened by replacing each
  370. // instance of GroupFixturePreparers with its contents.
  371. func GroupFixturePreparers(preparers ...FixturePreparer) FixturePreparer {
  372. all := dedupAndFlattenPreparers(nil, preparers)
  373. return newFixturePreparer(all)
  374. }
  375. // NullFixturePreparer is a preparer that does nothing.
  376. var NullFixturePreparer = GroupFixturePreparers()
  377. // OptionalFixturePreparer will return the supplied preparer if it is non-nil, otherwise it will
  378. // return the NullFixturePreparer
  379. func OptionalFixturePreparer(preparer FixturePreparer) FixturePreparer {
  380. if preparer == nil {
  381. return NullFixturePreparer
  382. } else {
  383. return preparer
  384. }
  385. }
  386. // FixturePreparer provides the ability to create, modify and then run tests within a fixture.
  387. type FixturePreparer interface {
  388. // Return the flattened and deduped list of simpleFixturePreparer pointers.
  389. list() []*simpleFixturePreparer
  390. // Create a Fixture.
  391. Fixture(t *testing.T) Fixture
  392. // ExtendWithErrorHandler creates a new FixturePreparer that will use the supplied error handler
  393. // to check the errors (may be 0) reported by the test.
  394. //
  395. // The default handlers is FixtureExpectsNoErrors which will fail the go test immediately if any
  396. // errors are reported.
  397. ExtendWithErrorHandler(errorHandler FixtureErrorHandler) FixturePreparer
  398. // Run the test, checking any errors reported and returning a TestResult instance.
  399. //
  400. // Shorthand for Fixture(t).RunTest()
  401. RunTest(t *testing.T) *TestResult
  402. // RunTestWithCustomResult runs the test just as RunTest(t) does but instead of returning a
  403. // *TestResult it returns the CustomTestResult that was returned by the custom
  404. // FixtureTestRunner.PostParseProcessor method that ran the test, or the *TestResult if that
  405. // method returned nil.
  406. //
  407. // This method must be used when needing to access custom data collected by the
  408. // FixtureTestRunner.PostParseProcessor method.
  409. //
  410. // e.g. something like this
  411. //
  412. // preparers := ...FixtureSetTestRunner(&myTestRunner)...
  413. // customResult := preparers.RunTestWithCustomResult(t).(*myCustomTestResult)
  414. // doSomething(customResult.data)
  415. RunTestWithCustomResult(t *testing.T) CustomTestResult
  416. // Run the test with the supplied Android.bp file.
  417. //
  418. // preparer.RunTestWithBp(t, bp) is shorthand for
  419. // android.GroupFixturePreparers(preparer, android.FixtureWithRootAndroidBp(bp)).RunTest(t)
  420. RunTestWithBp(t *testing.T, bp string) *TestResult
  421. // RunTestWithConfig is a temporary method added to help ease the migration of existing tests to
  422. // the test fixture.
  423. //
  424. // In order to allow the Config object to be customized separately to the TestContext a lot of
  425. // existing test code has `test...WithConfig` funcs that allow the Config object to be supplied
  426. // from the test and then have the TestContext created and configured automatically. e.g.
  427. // testCcWithConfig, testCcErrorWithConfig, testJavaWithConfig, etc.
  428. //
  429. // This method allows those methods to be migrated to use the test fixture pattern without
  430. // requiring that every test that uses those methods be migrated at the same time. That allows
  431. // those tests to benefit from correctness in the order of registration quickly.
  432. //
  433. // This method discards the config (along with its mock file system, product variables,
  434. // environment, etc.) that may have been set up by FixturePreparers.
  435. //
  436. // deprecated
  437. RunTestWithConfig(t *testing.T, config Config) *TestResult
  438. }
  439. // dedupAndFlattenPreparers removes any duplicates and flattens any composite FixturePreparer
  440. // instances.
  441. //
  442. // base - a list of already flattened and deduped preparers that will be applied first before
  443. //
  444. // the list of additional preparers. Any duplicates of these in the additional preparers
  445. // will be ignored.
  446. //
  447. // preparers - a list of additional unflattened, undeduped preparers that will be applied after the
  448. //
  449. // base preparers.
  450. //
  451. // Returns a deduped and flattened list of the preparers starting with the ones in base with any
  452. // additional ones from the preparers list added afterwards.
  453. func dedupAndFlattenPreparers(base []*simpleFixturePreparer, preparers []FixturePreparer) []*simpleFixturePreparer {
  454. if len(preparers) == 0 {
  455. return base
  456. }
  457. list := make([]*simpleFixturePreparer, len(base))
  458. visited := make(map[*simpleFixturePreparer]struct{})
  459. // Mark the already flattened and deduped preparers, if any, as having been seen so that
  460. // duplicates of these in the additional preparers will be discarded. Add them to the output
  461. // list.
  462. for i, s := range base {
  463. visited[s] = struct{}{}
  464. list[i] = s
  465. }
  466. for _, p := range preparers {
  467. for _, s := range p.list() {
  468. if _, seen := visited[s]; !seen {
  469. visited[s] = struct{}{}
  470. list = append(list, s)
  471. }
  472. }
  473. }
  474. return list
  475. }
  476. // compositeFixturePreparer is a FixturePreparer created from a list of fixture preparers.
  477. type compositeFixturePreparer struct {
  478. baseFixturePreparer
  479. // The flattened and deduped list of simpleFixturePreparer pointers encapsulated within this
  480. // composite preparer.
  481. preparers []*simpleFixturePreparer
  482. }
  483. func (c *compositeFixturePreparer) list() []*simpleFixturePreparer {
  484. return c.preparers
  485. }
  486. func newFixturePreparer(preparers []*simpleFixturePreparer) FixturePreparer {
  487. if len(preparers) == 1 {
  488. return preparers[0]
  489. }
  490. p := &compositeFixturePreparer{
  491. preparers: preparers,
  492. }
  493. p.initBaseFixturePreparer(p)
  494. return p
  495. }
  496. // simpleFixturePreparer is a FixturePreparer that applies a function to a fixture.
  497. type simpleFixturePreparer struct {
  498. baseFixturePreparer
  499. function func(fixture *fixture)
  500. }
  501. func (s *simpleFixturePreparer) list() []*simpleFixturePreparer {
  502. return []*simpleFixturePreparer{s}
  503. }
  504. func newSimpleFixturePreparer(preparer func(fixture *fixture)) FixturePreparer {
  505. p := &simpleFixturePreparer{function: preparer}
  506. p.initBaseFixturePreparer(p)
  507. return p
  508. }
  509. // FixtureErrorHandler determines how to respond to errors reported by the code under test.
  510. //
  511. // Some possible responses:
  512. // - Fail the test if any errors are reported, see FixtureExpectsNoErrors.
  513. // - Fail the test if at least one error that matches a pattern is not reported see
  514. // FixtureExpectsAtLeastOneErrorMatchingPattern
  515. // - Fail the test if any unexpected errors are reported.
  516. //
  517. // Although at the moment all the error handlers are implemented as simply a wrapper around a
  518. // function this is defined as an interface to allow future enhancements, e.g. provide different
  519. // ways other than patterns to match an error and to combine handlers together.
  520. type FixtureErrorHandler interface {
  521. // CheckErrors checks the errors reported.
  522. //
  523. // The supplied result can be used to access the state of the code under test just as the main
  524. // body of the test would but if any errors other than ones expected are reported the state may
  525. // be indeterminate.
  526. CheckErrors(t *testing.T, result *TestResult)
  527. }
  528. type simpleErrorHandler struct {
  529. function func(t *testing.T, result *TestResult)
  530. }
  531. func (h simpleErrorHandler) CheckErrors(t *testing.T, result *TestResult) {
  532. t.Helper()
  533. h.function(t, result)
  534. }
  535. // The default fixture error handler.
  536. //
  537. // Will fail the test immediately if any errors are reported.
  538. //
  539. // If the test fails this handler will call `result.FailNow()` which will exit the goroutine within
  540. // which the test is being run which means that the RunTest() method will not return.
  541. var FixtureExpectsNoErrors = FixtureCustomErrorHandler(
  542. func(t *testing.T, result *TestResult) {
  543. t.Helper()
  544. FailIfErrored(t, result.Errs)
  545. },
  546. )
  547. // FixtureIgnoreErrors ignores any errors.
  548. //
  549. // If this is used then it is the responsibility of the test to check the TestResult.Errs does not
  550. // contain any unexpected errors.
  551. var FixtureIgnoreErrors = FixtureCustomErrorHandler(func(t *testing.T, result *TestResult) {
  552. // Ignore the errors
  553. })
  554. // FixtureExpectsAtLeastOneMatchingError returns an error handler that will cause the test to fail
  555. // if at least one error that matches the regular expression is not found.
  556. //
  557. // The test will be failed if:
  558. // * No errors are reported.
  559. // * One or more errors are reported but none match the pattern.
  560. //
  561. // The test will not fail if:
  562. // * Multiple errors are reported that do not match the pattern as long as one does match.
  563. //
  564. // If the test fails this handler will call `result.FailNow()` which will exit the goroutine within
  565. // which the test is being run which means that the RunTest() method will not return.
  566. func FixtureExpectsAtLeastOneErrorMatchingPattern(pattern string) FixtureErrorHandler {
  567. return FixtureCustomErrorHandler(func(t *testing.T, result *TestResult) {
  568. t.Helper()
  569. if !FailIfNoMatchingErrors(t, pattern, result.Errs) {
  570. t.FailNow()
  571. }
  572. })
  573. }
  574. // FixtureExpectsOneErrorToMatchPerPattern returns an error handler that will cause the test to fail
  575. // if there are any unexpected errors.
  576. //
  577. // The test will be failed if:
  578. // * The number of errors reported does not exactly match the patterns.
  579. // * One or more of the reported errors do not match a pattern.
  580. // * No patterns are provided and one or more errors are reported.
  581. //
  582. // The test will not fail if:
  583. // * One or more of the patterns does not match an error.
  584. //
  585. // If the test fails this handler will call `result.FailNow()` which will exit the goroutine within
  586. // which the test is being run which means that the RunTest() method will not return.
  587. func FixtureExpectsAllErrorsToMatchAPattern(patterns []string) FixtureErrorHandler {
  588. return FixtureCustomErrorHandler(func(t *testing.T, result *TestResult) {
  589. t.Helper()
  590. CheckErrorsAgainstExpectations(t, result.Errs, patterns)
  591. })
  592. }
  593. // FixtureExpectsOneErrorPattern returns an error handler that will cause the test to fail
  594. // if there is more than one error or the error does not match the pattern.
  595. //
  596. // If the test fails this handler will call `result.FailNow()` which will exit the goroutine within
  597. // which the test is being run which means that the RunTest() method will not return.
  598. func FixtureExpectsOneErrorPattern(pattern string) FixtureErrorHandler {
  599. return FixtureCustomErrorHandler(func(t *testing.T, result *TestResult) {
  600. t.Helper()
  601. CheckErrorsAgainstExpectations(t, result.Errs, []string{pattern})
  602. })
  603. }
  604. // FixtureCustomErrorHandler creates a custom error handler
  605. func FixtureCustomErrorHandler(function func(t *testing.T, result *TestResult)) FixtureErrorHandler {
  606. return simpleErrorHandler{
  607. function: function,
  608. }
  609. }
  610. // Fixture defines the test environment.
  611. type Fixture interface {
  612. // Config returns the fixture's configuration.
  613. Config() Config
  614. // Context returns the fixture's test context.
  615. Context() *TestContext
  616. // MockFS returns the fixture's mock filesystem.
  617. MockFS() MockFS
  618. // Run the test, checking any errors reported and returning a TestResult instance.
  619. RunTest() CustomTestResult
  620. }
  621. // Struct to allow TestResult to embed a *TestContext and allow call forwarding to its methods.
  622. type testContext struct {
  623. *TestContext
  624. }
  625. // The result of running a test.
  626. type TestResult struct {
  627. testContext
  628. fixture *fixture
  629. Config Config
  630. // The errors that were reported during the test.
  631. Errs []error
  632. // The ninja deps is a list of the ninja files dependencies that were added by the modules and
  633. // singletons via the *.AddNinjaFileDeps() methods.
  634. NinjaDeps []string
  635. }
  636. func (r *TestResult) testResult() *TestResult { return r }
  637. // CustomTestResult is the interface that FixtureTestRunner implementations who wish to return
  638. // custom data must implement. It must embed *TestResult and initialize that to the value passed
  639. // into the method. It is returned from the FixtureTestRunner.FinalPreparer, passed into the
  640. // FixtureTestRunner.PostParseProcessor and returned from FixturePreparer.RunTestWithCustomResult.
  641. //
  642. // e.g. something like this:
  643. //
  644. // type myCustomTestResult struct {
  645. // *android.TestResult
  646. // data []string
  647. // }
  648. //
  649. // func (r *myTestRunner) FinalPreparer(result *TestResult) CustomTestResult {
  650. // ... do some final test preparation ...
  651. // return &myCustomTestResult{TestResult: result)
  652. // }
  653. //
  654. // func (r *myTestRunner) PostParseProcessor(result CustomTestResult) {
  655. // ...
  656. // myData := []string {....}
  657. // ...
  658. // customResult := result.(*myCustomTestResult)
  659. // customResult.data = myData
  660. // }
  661. type CustomTestResult interface {
  662. // testResult returns the embedded *TestResult.
  663. testResult() *TestResult
  664. }
  665. var _ CustomTestResult = (*TestResult)(nil)
  666. type TestPathContext struct {
  667. *TestResult
  668. }
  669. var _ PathContext = &TestPathContext{}
  670. func (t *TestPathContext) Config() Config {
  671. return t.TestResult.Config
  672. }
  673. func (t *TestPathContext) AddNinjaFileDeps(deps ...string) {
  674. panic("unimplemented")
  675. }
  676. func createFixture(t *testing.T, buildDir string, preparers []*simpleFixturePreparer) Fixture {
  677. config := TestConfig(buildDir, nil, "", nil)
  678. ctx := newTestContextForFixture(config)
  679. fixture := &fixture{
  680. preparers: preparers,
  681. t: t,
  682. config: config,
  683. ctx: ctx,
  684. mockFS: make(MockFS),
  685. // Set the default error handler.
  686. errorHandler: FixtureExpectsNoErrors,
  687. }
  688. for _, preparer := range preparers {
  689. preparer.function(fixture)
  690. }
  691. return fixture
  692. }
  693. type baseFixturePreparer struct {
  694. self FixturePreparer
  695. }
  696. func (b *baseFixturePreparer) initBaseFixturePreparer(self FixturePreparer) {
  697. b.self = self
  698. }
  699. func (b *baseFixturePreparer) Fixture(t *testing.T) Fixture {
  700. return createFixture(t, t.TempDir(), b.self.list())
  701. }
  702. func (b *baseFixturePreparer) ExtendWithErrorHandler(errorHandler FixtureErrorHandler) FixturePreparer {
  703. return GroupFixturePreparers(b.self, newSimpleFixturePreparer(func(fixture *fixture) {
  704. fixture.errorHandler = errorHandler
  705. }))
  706. }
  707. func (b *baseFixturePreparer) RunTest(t *testing.T) *TestResult {
  708. t.Helper()
  709. return b.RunTestWithCustomResult(t).testResult()
  710. }
  711. func (b *baseFixturePreparer) RunTestWithCustomResult(t *testing.T) CustomTestResult {
  712. t.Helper()
  713. fixture := b.self.Fixture(t)
  714. return fixture.RunTest()
  715. }
  716. func (b *baseFixturePreparer) RunTestWithBp(t *testing.T, bp string) *TestResult {
  717. t.Helper()
  718. return GroupFixturePreparers(b.self, FixtureWithRootAndroidBp(bp)).RunTest(t)
  719. }
  720. func (b *baseFixturePreparer) RunTestWithConfig(t *testing.T, config Config) *TestResult {
  721. t.Helper()
  722. // Create the fixture as normal.
  723. fixture := b.self.Fixture(t).(*fixture)
  724. // Discard the mock filesystem as otherwise that will override the one in the config.
  725. fixture.mockFS = nil
  726. // Replace the config with the supplied one in the fixture.
  727. fixture.config = config
  728. // Ditto with config derived information in the TestContext.
  729. ctx := fixture.ctx
  730. ctx.config = config
  731. ctx.SetFs(ctx.config.fs)
  732. if ctx.config.mockBpList != "" {
  733. ctx.SetModuleListFile(ctx.config.mockBpList)
  734. }
  735. return fixture.RunTest().testResult()
  736. }
  737. type fixture struct {
  738. // The preparers used to create this fixture.
  739. preparers []*simpleFixturePreparer
  740. // The test runner used in this fixture, defaults to defaultTestRunner if not set.
  741. testRunner FixtureTestRunner
  742. // The gotest state of the go test within which this was created.
  743. t *testing.T
  744. // The configuration prepared for this fixture.
  745. config Config
  746. // The test context prepared for this fixture.
  747. ctx *TestContext
  748. // The mock filesystem prepared for this fixture.
  749. mockFS MockFS
  750. // The error handler used to check the errors, if any, that are reported.
  751. errorHandler FixtureErrorHandler
  752. // Debug mode status
  753. debug bool
  754. }
  755. func (f *fixture) Config() Config {
  756. return f.config
  757. }
  758. func (f *fixture) Context() *TestContext {
  759. return f.ctx
  760. }
  761. func (f *fixture) MockFS() MockFS {
  762. return f.mockFS
  763. }
  764. func (f *fixture) RunTest() CustomTestResult {
  765. f.t.Helper()
  766. // If in debug mode output the state of the fixture before running the test.
  767. if f.debug {
  768. f.outputDebugState()
  769. }
  770. ctx := f.ctx
  771. // Do not use the fixture's mockFS to initialize the config's mock file system if it has been
  772. // cleared by RunTestWithConfig.
  773. if f.mockFS != nil {
  774. // The TestConfig() method assumes that the mock filesystem is available when creating so
  775. // creates the mock file system immediately. Similarly, the NewTestContext(Config) method
  776. // assumes that the supplied Config's FileSystem has been properly initialized before it is
  777. // called and so it takes its own reference to the filesystem. However, fixtures create the
  778. // Config and TestContext early so they can be modified by preparers at which time the mockFS
  779. // has not been populated (because it too is modified by preparers). So, this reinitializes the
  780. // Config and TestContext's FileSystem using the now populated mockFS.
  781. f.config.mockFileSystem("", f.mockFS)
  782. ctx.SetFs(ctx.config.fs)
  783. if ctx.config.mockBpList != "" {
  784. ctx.SetModuleListFile(ctx.config.mockBpList)
  785. }
  786. }
  787. // Create and set the Context's NameInterface. It needs to be created here as it depends on the
  788. // configuration that has been prepared for this fixture.
  789. resolver := NewNameResolver(ctx.config)
  790. // Set the NameInterface in the main Context.
  791. ctx.SetNameInterface(resolver)
  792. // Set the NameResolver in the TestContext.
  793. ctx.NameResolver = resolver
  794. // If test runner has not been set then use the default runner.
  795. if f.testRunner == nil {
  796. f.testRunner = defaultTestRunner
  797. }
  798. // Create the result to collate result information.
  799. result := &TestResult{
  800. testContext: testContext{ctx},
  801. fixture: f,
  802. Config: f.config,
  803. }
  804. // Do any last minute preparation before parsing the blueprint files.
  805. customResult := f.testRunner.FinalPreparer(result)
  806. // Parse the blueprint files adding the information to the result.
  807. extraNinjaDeps, errs := ctx.ParseBlueprintsFiles("ignored")
  808. result.NinjaDeps = append(result.NinjaDeps, extraNinjaDeps...)
  809. result.Errs = append(result.Errs, errs...)
  810. if len(result.Errs) == 0 {
  811. // If parsing the blueprint files was successful then perform any additional processing.
  812. f.testRunner.PostParseProcessor(customResult)
  813. }
  814. f.errorHandler.CheckErrors(f.t, result)
  815. return customResult
  816. }
  817. // standardTestRunner is the implementation of the default test runner
  818. type standardTestRunner struct{}
  819. func (s *standardTestRunner) FinalPreparer(result *TestResult) CustomTestResult {
  820. // Register the hard coded mutators and singletons used by the standard Soong build as well as
  821. // any additional instances that have been registered with this fixture.
  822. result.TestContext.Register()
  823. return result
  824. }
  825. func (s *standardTestRunner) PostParseProcessor(customResult CustomTestResult) {
  826. result := customResult.(*TestResult)
  827. ctx := result.TestContext
  828. cfg := result.Config
  829. // Prepare the build actions, i.e. run all the mutators, singletons and then invoke the
  830. // GenerateAndroidBuildActions methods on all the modules.
  831. extraNinjaDeps, errs := ctx.PrepareBuildActions(cfg)
  832. result.NinjaDeps = append(result.NinjaDeps, extraNinjaDeps...)
  833. result.CollateErrs(errs)
  834. }
  835. var defaultTestRunner FixtureTestRunner = &standardTestRunner{}
  836. func (f *fixture) outputDebugState() {
  837. fmt.Printf("Begin Fixture State for %s\n", f.t.Name())
  838. if len(f.config.env) == 0 {
  839. fmt.Printf(" Fixture Env is empty\n")
  840. } else {
  841. fmt.Printf(" Begin Env\n")
  842. for k, v := range f.config.env {
  843. fmt.Printf(" - %s=%s\n", k, v)
  844. }
  845. fmt.Printf(" End Env\n")
  846. }
  847. if len(f.mockFS) == 0 {
  848. fmt.Printf(" Mock FS is empty\n")
  849. } else {
  850. fmt.Printf(" Begin Mock FS Contents\n")
  851. for p, c := range f.mockFS {
  852. if c == nil {
  853. fmt.Printf("\n - %s: nil\n", p)
  854. } else {
  855. contents := string(c)
  856. separator := " ========================================================================"
  857. fmt.Printf(" - %s\n%s\n", p, separator)
  858. for i, line := range strings.Split(contents, "\n") {
  859. fmt.Printf(" %6d: %s\n", i+1, line)
  860. }
  861. fmt.Printf("%s\n", separator)
  862. }
  863. }
  864. fmt.Printf(" End Mock FS Contents\n")
  865. }
  866. fmt.Printf("End Fixture State for %s\n", f.t.Name())
  867. }
  868. // NormalizePathForTesting removes the test invocation specific build directory from the supplied
  869. // path.
  870. //
  871. // If the path is within the build directory (e.g. an OutputPath) then this returns the relative
  872. // path to avoid tests having to deal with the dynamically generated build directory.
  873. //
  874. // Otherwise, this returns the supplied path as it is almost certainly a source path that is
  875. // relative to the root of the source tree.
  876. //
  877. // Even though some information is removed from some paths and not others it should be possible to
  878. // differentiate between them by the paths themselves, e.g. output paths will likely include
  879. // ".intermediates" but source paths won't.
  880. func (r *TestResult) NormalizePathForTesting(path Path) string {
  881. pathContext := PathContextForTesting(r.Config)
  882. pathAsString := path.String()
  883. if rel, isRel := MaybeRel(pathContext, r.Config.SoongOutDir(), pathAsString); isRel {
  884. return rel
  885. }
  886. return pathAsString
  887. }
  888. // NormalizePathsForTesting normalizes each path in the supplied list and returns their normalized
  889. // forms.
  890. func (r *TestResult) NormalizePathsForTesting(paths Paths) []string {
  891. var result []string
  892. for _, path := range paths {
  893. result = append(result, r.NormalizePathForTesting(path))
  894. }
  895. return result
  896. }
  897. // Preparer will return a FixturePreparer encapsulating all the preparers used to create the fixture
  898. // that produced this result.
  899. //
  900. // e.g. assuming that this result was created by running:
  901. //
  902. // GroupFixturePreparers(preparer1, preparer2, preparer3).RunTest(t)
  903. //
  904. // Then this method will be equivalent to running:
  905. //
  906. // GroupFixturePreparers(preparer1, preparer2, preparer3)
  907. //
  908. // This is intended for use by tests whose output is Android.bp files to verify that those files
  909. // are valid, e.g. tests of the snapshots produced by the sdk module type.
  910. func (r *TestResult) Preparer() FixturePreparer {
  911. return newFixturePreparer(r.fixture.preparers)
  912. }
  913. // Module returns the module with the specific name and of the specified variant.
  914. func (r *TestResult) Module(name string, variant string) Module {
  915. return r.ModuleForTests(name, variant).Module()
  916. }
  917. // CollateErrs adds additional errors to the result and returns true if there is more than one
  918. // error in the result.
  919. func (r *TestResult) CollateErrs(errs []error) bool {
  920. r.Errs = append(r.Errs, errs...)
  921. return len(r.Errs) > 0
  922. }