github.com/westcoastroms/westcoastroms-build@v0.0.0-20190928114312-2350e5a73030/build/soong/android/namespace_test.go (about)

     1  // Copyright 2017 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  
    15  package android
    16  
    17  import (
    18  	"errors"
    19  	"io/ioutil"
    20  	"os"
    21  	"path/filepath"
    22  	"reflect"
    23  	"testing"
    24  
    25  	"github.com/google/blueprint"
    26  )
    27  
    28  func TestDependingOnModuleInSameNamespace(t *testing.T) {
    29  	ctx := setupTest(t,
    30  		map[string]string{
    31  			"dir1": `
    32  			soong_namespace {
    33  			}
    34  			test_module {
    35  				name: "a",
    36  			}
    37  			test_module {
    38  				name: "b",
    39  				deps: ["a"],
    40  			}
    41  			`,
    42  		},
    43  	)
    44  
    45  	a := getModule(ctx, "a")
    46  	b := getModule(ctx, "b")
    47  	if !dependsOn(ctx, b, a) {
    48  		t.Errorf("module b does not depend on module a in the same namespace")
    49  	}
    50  }
    51  
    52  func TestDependingOnModuleInRootNamespace(t *testing.T) {
    53  	ctx := setupTest(t,
    54  		map[string]string{
    55  			".": `
    56  			test_module {
    57  				name: "b",
    58  				deps: ["a"],
    59  			}
    60  			test_module {
    61  				name: "a",
    62  			}
    63  			`,
    64  		},
    65  	)
    66  
    67  	a := getModule(ctx, "a")
    68  	b := getModule(ctx, "b")
    69  	if !dependsOn(ctx, b, a) {
    70  		t.Errorf("module b in root namespace does not depend on module a in the root namespace")
    71  	}
    72  }
    73  
    74  func TestImplicitlyImportRootNamespace(t *testing.T) {
    75  	_ = setupTest(t,
    76  		map[string]string{
    77  			".": `
    78  			test_module {
    79  				name: "a",
    80  			}
    81  			`,
    82  			"dir1": `
    83  			soong_namespace {
    84  			}
    85  			test_module {
    86  				name: "b",
    87  				deps: ["a"],
    88  			}
    89  			`,
    90  		},
    91  	)
    92  
    93  	// setupTest will report any errors
    94  }
    95  
    96  func TestDependingOnModuleInImportedNamespace(t *testing.T) {
    97  	ctx := setupTest(t,
    98  		map[string]string{
    99  			"dir1": `
   100  			soong_namespace {
   101  			}
   102  			test_module {
   103  				name: "a",
   104  			}
   105  			`,
   106  			"dir2": `
   107  			soong_namespace {
   108  				imports: ["dir1"],
   109  			}
   110  			test_module {
   111  				name: "b",
   112  				deps: ["a"],
   113  			}
   114  			`,
   115  		},
   116  	)
   117  
   118  	a := getModule(ctx, "a")
   119  	b := getModule(ctx, "b")
   120  	if !dependsOn(ctx, b, a) {
   121  		t.Errorf("module b does not depend on module a in the same namespace")
   122  	}
   123  }
   124  
   125  func TestDependingOnModuleInNonImportedNamespace(t *testing.T) {
   126  	_, errs := setupTestExpectErrs(
   127  		map[string]string{
   128  			"dir1": `
   129  			soong_namespace {
   130  			}
   131  			test_module {
   132  				name: "a",
   133  			}
   134  			`,
   135  			"dir2": `
   136  			soong_namespace {
   137  			}
   138  			test_module {
   139  				name: "a",
   140  			}
   141  			`,
   142  			"dir3": `
   143  			soong_namespace {
   144  			}
   145  			test_module {
   146  				name: "b",
   147  				deps: ["a"],
   148  			}
   149  			`,
   150  		},
   151  	)
   152  
   153  	expectedErrors := []error{
   154  		errors.New(
   155  			`dir3/Android.bp:4:4: "b" depends on undefined module "a"
   156  Module "b" is defined in namespace "dir3" which can read these 2 namespaces: ["dir3" "."]
   157  Module "a" can be found in these namespaces: ["dir1" "dir2"]`),
   158  	}
   159  
   160  	if len(errs) != 1 || errs[0].Error() != expectedErrors[0].Error() {
   161  		t.Errorf("Incorrect errors. Expected:\n%v\n, got:\n%v\n", expectedErrors, errs)
   162  	}
   163  }
   164  
   165  func TestDependingOnModuleByFullyQualifiedReference(t *testing.T) {
   166  	ctx := setupTest(t,
   167  		map[string]string{
   168  			"dir1": `
   169  			soong_namespace {
   170  			}
   171  			test_module {
   172  				name: "a",
   173  			}
   174  			`,
   175  			"dir2": `
   176  			soong_namespace {
   177  			}
   178  			test_module {
   179  				name: "b",
   180  				deps: ["//dir1:a"],
   181  			}
   182  			`,
   183  		},
   184  	)
   185  	a := getModule(ctx, "a")
   186  	b := getModule(ctx, "b")
   187  	if !dependsOn(ctx, b, a) {
   188  		t.Errorf("module b does not depend on module a")
   189  	}
   190  }
   191  
   192  func TestSameNameInTwoNamespaces(t *testing.T) {
   193  	ctx := setupTest(t,
   194  		map[string]string{
   195  			"dir1": `
   196  			soong_namespace {
   197  			}
   198  			test_module {
   199  				name: "a",
   200  				id: "1",
   201  			}
   202  			test_module {
   203  				name: "b",
   204  				deps: ["a"],
   205  				id: "2",
   206  			}
   207  			`,
   208  			"dir2": `
   209  			soong_namespace {
   210  			}
   211  			test_module {
   212  				name: "a",
   213  				id:"3",
   214  			}
   215  			test_module {
   216  				name: "b",
   217  				deps: ["a"],
   218  				id:"4",
   219  			}
   220  			`,
   221  		},
   222  	)
   223  
   224  	one := findModuleById(ctx, "1")
   225  	two := findModuleById(ctx, "2")
   226  	three := findModuleById(ctx, "3")
   227  	four := findModuleById(ctx, "4")
   228  	if !dependsOn(ctx, two, one) {
   229  		t.Fatalf("Module 2 does not depend on module 1 in its namespace")
   230  	}
   231  	if dependsOn(ctx, two, three) {
   232  		t.Fatalf("Module 2 depends on module 3 in another namespace")
   233  	}
   234  	if !dependsOn(ctx, four, three) {
   235  		t.Fatalf("Module 4 does not depend on module 3 in its namespace")
   236  	}
   237  	if dependsOn(ctx, four, one) {
   238  		t.Fatalf("Module 4 depends on module 1 in another namespace")
   239  	}
   240  }
   241  
   242  func TestSearchOrder(t *testing.T) {
   243  	ctx := setupTest(t,
   244  		map[string]string{
   245  			"dir1": `
   246  			soong_namespace {
   247  			}
   248  			test_module {
   249  				name: "a",
   250  				id: "1",
   251  			}
   252  			`,
   253  			"dir2": `
   254  			soong_namespace {
   255  			}
   256  			test_module {
   257  				name: "a",
   258  				id:"2",
   259  			}
   260  			test_module {
   261  				name: "b",
   262  				id:"3",
   263  			}
   264  			`,
   265  			"dir3": `
   266  			soong_namespace {
   267  			}
   268  			test_module {
   269  				name: "a",
   270  				id:"4",
   271  			}
   272  			test_module {
   273  				name: "b",
   274  				id:"5",
   275  			}
   276  			test_module {
   277  				name: "c",
   278  				id:"6",
   279  			}
   280  			`,
   281  			".": `
   282  			test_module {
   283  				name: "a",
   284  				id: "7",
   285  			}
   286  			test_module {
   287  				name: "b",
   288  				id: "8",
   289  			}
   290  			test_module {
   291  				name: "c",
   292  				id: "9",
   293  			}
   294  			test_module {
   295  				name: "d",
   296  				id: "10",
   297  			}
   298  			`,
   299  			"dir4": `
   300  			soong_namespace {
   301  				imports: ["dir1", "dir2", "dir3"]
   302  			}
   303  			test_module {
   304  				name: "test_me",
   305  				id:"0",
   306  				deps: ["a", "b", "c", "d"],
   307  			}
   308  			`,
   309  		},
   310  	)
   311  
   312  	testMe := findModuleById(ctx, "0")
   313  	if !dependsOn(ctx, testMe, findModuleById(ctx, "1")) {
   314  		t.Errorf("test_me doesn't depend on id 1")
   315  	}
   316  	if !dependsOn(ctx, testMe, findModuleById(ctx, "3")) {
   317  		t.Errorf("test_me doesn't depend on id 3")
   318  	}
   319  	if !dependsOn(ctx, testMe, findModuleById(ctx, "6")) {
   320  		t.Errorf("test_me doesn't depend on id 6")
   321  	}
   322  	if !dependsOn(ctx, testMe, findModuleById(ctx, "10")) {
   323  		t.Errorf("test_me doesn't depend on id 10")
   324  	}
   325  	if numDeps(ctx, testMe) != 4 {
   326  		t.Errorf("num dependencies of test_me = %v, not 4\n", numDeps(ctx, testMe))
   327  	}
   328  }
   329  
   330  func TestTwoNamespacesCanImportEachOther(t *testing.T) {
   331  	_ = setupTest(t,
   332  		map[string]string{
   333  			"dir1": `
   334  			soong_namespace {
   335  				imports: ["dir2"]
   336  			}
   337  			test_module {
   338  				name: "a",
   339  			}
   340  			test_module {
   341  				name: "c",
   342  				deps: ["b"],
   343  			}
   344  			`,
   345  			"dir2": `
   346  			soong_namespace {
   347  				imports: ["dir1"],
   348  			}
   349  			test_module {
   350  				name: "b",
   351  				deps: ["a"],
   352  			}
   353  			`,
   354  		},
   355  	)
   356  
   357  	// setupTest will report any errors
   358  }
   359  
   360  func TestImportingNonexistentNamespace(t *testing.T) {
   361  	_, errs := setupTestExpectErrs(
   362  		map[string]string{
   363  			"dir1": `
   364  			soong_namespace {
   365  				imports: ["a_nonexistent_namespace"]
   366  			}
   367  			test_module {
   368  				name: "a",
   369  				deps: ["a_nonexistent_module"]
   370  			}
   371  			`,
   372  		},
   373  	)
   374  
   375  	// should complain about the missing namespace and not complain about the unresolvable dependency
   376  	expectedErrors := []error{
   377  		errors.New(`dir1/Android.bp:2:4: module "soong_namespace": namespace a_nonexistent_namespace does not exist`),
   378  	}
   379  	if len(errs) != 1 || errs[0].Error() != expectedErrors[0].Error() {
   380  		t.Errorf("Incorrect errors. Expected:\n%v\n, got:\n%v\n", expectedErrors, errs)
   381  	}
   382  }
   383  
   384  func TestNamespacesDontInheritParentNamespaces(t *testing.T) {
   385  	_, errs := setupTestExpectErrs(
   386  		map[string]string{
   387  			"dir1": `
   388  			soong_namespace {
   389  			}
   390  			test_module {
   391  				name: "a",
   392  			}
   393  			`,
   394  			"dir1/subdir1": `
   395  			soong_namespace {
   396  			}
   397  			test_module {
   398  				name: "b",
   399  				deps: ["a"],
   400  			}
   401  			`,
   402  		},
   403  	)
   404  
   405  	expectedErrors := []error{
   406  		errors.New(`dir1/subdir1/Android.bp:4:4: "b" depends on undefined module "a"
   407  Module "b" is defined in namespace "dir1/subdir1" which can read these 2 namespaces: ["dir1/subdir1" "."]
   408  Module "a" can be found in these namespaces: ["dir1"]`),
   409  	}
   410  	if len(errs) != 1 || errs[0].Error() != expectedErrors[0].Error() {
   411  		t.Errorf("Incorrect errors. Expected:\n%v\n, got:\n%v\n", expectedErrors, errs)
   412  	}
   413  }
   414  
   415  func TestModulesDoReceiveParentNamespace(t *testing.T) {
   416  	_ = setupTest(t,
   417  		map[string]string{
   418  			"dir1": `
   419  			soong_namespace {
   420  			}
   421  			test_module {
   422  				name: "a",
   423  			}
   424  			`,
   425  			"dir1/subdir": `
   426  			test_module {
   427  				name: "b",
   428  				deps: ["a"],
   429  			}
   430  			`,
   431  		},
   432  	)
   433  
   434  	// setupTest will report any errors
   435  }
   436  
   437  func TestNamespaceImportsNotTransitive(t *testing.T) {
   438  	_, errs := setupTestExpectErrs(
   439  		map[string]string{
   440  			"dir1": `
   441  			soong_namespace {
   442  			}
   443  			test_module {
   444  				name: "a",
   445  			}
   446  			`,
   447  			"dir2": `
   448  			soong_namespace {
   449  				imports: ["dir1"],
   450  			}
   451  			test_module {
   452  				name: "b",
   453  				deps: ["a"],
   454  			}
   455  			`,
   456  			"dir3": `
   457  			soong_namespace {
   458  				imports: ["dir2"],
   459  			}
   460  			test_module {
   461  				name: "c",
   462  				deps: ["a"],
   463  			}
   464  			`,
   465  		},
   466  	)
   467  
   468  	expectedErrors := []error{
   469  		errors.New(`dir3/Android.bp:5:4: "c" depends on undefined module "a"
   470  Module "c" is defined in namespace "dir3" which can read these 3 namespaces: ["dir3" "dir2" "."]
   471  Module "a" can be found in these namespaces: ["dir1"]`),
   472  	}
   473  	if len(errs) != 1 || errs[0].Error() != expectedErrors[0].Error() {
   474  		t.Errorf("Incorrect errors. Expected:\n%v\n, got:\n%v\n", expectedErrors, errs)
   475  	}
   476  }
   477  
   478  func TestTwoNamepacesInSameDir(t *testing.T) {
   479  	_, errs := setupTestExpectErrs(
   480  		map[string]string{
   481  			"dir1": `
   482  			soong_namespace {
   483  			}
   484  			soong_namespace {
   485  			}
   486  			`,
   487  		},
   488  	)
   489  
   490  	expectedErrors := []error{
   491  		errors.New(`dir1/Android.bp:4:4: namespace dir1 already exists`),
   492  	}
   493  	if len(errs) != 1 || errs[0].Error() != expectedErrors[0].Error() {
   494  		t.Errorf("Incorrect errors. Expected:\n%v\n, got:\n%v\n", expectedErrors, errs)
   495  	}
   496  }
   497  
   498  func TestNamespaceNotAtTopOfFile(t *testing.T) {
   499  	_, errs := setupTestExpectErrs(
   500  		map[string]string{
   501  			"dir1": `
   502  			test_module {
   503  				name: "a"
   504  			}
   505  			soong_namespace {
   506  			}
   507  			`,
   508  		},
   509  	)
   510  
   511  	expectedErrors := []error{
   512  		errors.New(`dir1/Android.bp:5:4: a namespace must be the first module in the file`),
   513  	}
   514  	if len(errs) != 1 || errs[0].Error() != expectedErrors[0].Error() {
   515  		t.Errorf("Incorrect errors. Expected:\n%v\n, got:\n%v\n", expectedErrors, errs)
   516  	}
   517  }
   518  
   519  func TestTwoModulesWithSameNameInSameNamespace(t *testing.T) {
   520  	_, errs := setupTestExpectErrs(
   521  		map[string]string{
   522  			"dir1": `
   523  			soong_namespace {
   524  			}
   525  			test_module {
   526  				name: "a"
   527  			}
   528  			test_module {
   529  				name: "a"
   530  			}
   531  			`,
   532  		},
   533  	)
   534  
   535  	expectedErrors := []error{
   536  		errors.New(`dir1/Android.bp:7:4: module "a" already defined
   537         dir1/Android.bp:4:4 <-- previous definition here`),
   538  	}
   539  	if len(errs) != 1 || errs[0].Error() != expectedErrors[0].Error() {
   540  		t.Errorf("Incorrect errors. Expected:\n%v\n, got:\n%v\n", expectedErrors, errs)
   541  	}
   542  }
   543  
   544  func TestDeclaringNamespaceInNonAndroidBpFile(t *testing.T) {
   545  	_, errs := setupTestFromFiles(
   546  		map[string][]byte{
   547  			"Android.bp": []byte(`
   548  				build = ["include.bp"]
   549  			`),
   550  			"include.bp": []byte(`
   551  				soong_namespace {
   552  				}
   553  			`),
   554  		},
   555  	)
   556  
   557  	expectedErrors := []error{
   558  		errors.New(`include.bp:2:5: A namespace may only be declared in a file named Android.bp`),
   559  	}
   560  
   561  	if len(errs) != 1 || errs[0].Error() != expectedErrors[0].Error() {
   562  		t.Errorf("Incorrect errors. Expected:\n%v\n, got:\n%v\n", expectedErrors, errs)
   563  	}
   564  }
   565  
   566  // so that the generated .ninja file will have consistent names
   567  func TestConsistentNamespaceNames(t *testing.T) {
   568  	ctx := setupTest(t,
   569  		map[string]string{
   570  			"dir1": "soong_namespace{}",
   571  			"dir2": "soong_namespace{}",
   572  			"dir3": "soong_namespace{}",
   573  		})
   574  
   575  	ns1, _ := ctx.NameResolver.namespaceAt("dir1")
   576  	ns2, _ := ctx.NameResolver.namespaceAt("dir2")
   577  	ns3, _ := ctx.NameResolver.namespaceAt("dir3")
   578  	actualIds := []string{ns1.id, ns2.id, ns3.id}
   579  	expectedIds := []string{"1", "2", "3"}
   580  	if !reflect.DeepEqual(actualIds, expectedIds) {
   581  		t.Errorf("Incorrect namespace ids.\nactual: %s\nexpected: %s\n", actualIds, expectedIds)
   582  	}
   583  }
   584  
   585  // so that the generated .ninja file will have consistent names
   586  func TestRename(t *testing.T) {
   587  	_ = setupTest(t,
   588  		map[string]string{
   589  			"dir1": `
   590  			soong_namespace {
   591  			}
   592  			test_module {
   593  				name: "a",
   594  				deps: ["c"],
   595  			}
   596  			test_module {
   597  				name: "b",
   598  				rename: "c",
   599  			}
   600  		`})
   601  	// setupTest will report any errors
   602  }
   603  
   604  // some utils to support the tests
   605  
   606  func mockFiles(bps map[string]string) (files map[string][]byte) {
   607  	files = make(map[string][]byte, len(bps))
   608  	files["Android.bp"] = []byte("")
   609  	for dir, text := range bps {
   610  		files[filepath.Join(dir, "Android.bp")] = []byte(text)
   611  	}
   612  	return files
   613  }
   614  
   615  func setupTestFromFiles(bps map[string][]byte) (ctx *TestContext, errs []error) {
   616  	buildDir, err := ioutil.TempDir("", "soong_namespace_test")
   617  	if err != nil {
   618  		return nil, []error{err}
   619  	}
   620  	defer os.RemoveAll(buildDir)
   621  
   622  	config := TestConfig(buildDir, nil)
   623  
   624  	ctx = NewTestContext()
   625  	ctx.MockFileSystem(bps)
   626  	ctx.RegisterModuleType("test_module", ModuleFactoryAdaptor(newTestModule))
   627  	ctx.RegisterModuleType("soong_namespace", ModuleFactoryAdaptor(NamespaceFactory))
   628  	ctx.PreArchMutators(RegisterNamespaceMutator)
   629  	ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
   630  		ctx.BottomUp("rename", renameMutator)
   631  	})
   632  	ctx.Register()
   633  
   634  	_, errs = ctx.ParseBlueprintsFiles("Android.bp")
   635  	if len(errs) > 0 {
   636  		return ctx, errs
   637  	}
   638  	_, errs = ctx.PrepareBuildActions(config)
   639  	return ctx, errs
   640  }
   641  
   642  func setupTestExpectErrs(bps map[string]string) (ctx *TestContext, errs []error) {
   643  	files := make(map[string][]byte, len(bps))
   644  	files["Android.bp"] = []byte("")
   645  	for dir, text := range bps {
   646  		files[filepath.Join(dir, "Android.bp")] = []byte(text)
   647  	}
   648  	return setupTestFromFiles(files)
   649  }
   650  
   651  func setupTest(t *testing.T, bps map[string]string) (ctx *TestContext) {
   652  	ctx, errs := setupTestExpectErrs(bps)
   653  	FailIfErrored(t, errs)
   654  	return ctx
   655  }
   656  
   657  func dependsOn(ctx *TestContext, module TestingModule, possibleDependency TestingModule) bool {
   658  	depends := false
   659  	visit := func(dependency blueprint.Module) {
   660  		if dependency == possibleDependency.module {
   661  			depends = true
   662  		}
   663  	}
   664  	ctx.VisitDirectDeps(module.module, visit)
   665  	return depends
   666  }
   667  
   668  func numDeps(ctx *TestContext, module TestingModule) int {
   669  	count := 0
   670  	visit := func(dependency blueprint.Module) {
   671  		count++
   672  	}
   673  	ctx.VisitDirectDeps(module.module, visit)
   674  	return count
   675  }
   676  
   677  func getModule(ctx *TestContext, moduleName string) TestingModule {
   678  	return ctx.ModuleForTests(moduleName, "")
   679  }
   680  
   681  func findModuleById(ctx *TestContext, id string) (module TestingModule) {
   682  	visit := func(candidate blueprint.Module) {
   683  		testModule, ok := candidate.(*testModule)
   684  		if ok {
   685  			if testModule.properties.Id == id {
   686  				module = TestingModule{testModule}
   687  			}
   688  		}
   689  	}
   690  	ctx.VisitAllModules(visit)
   691  	return module
   692  }
   693  
   694  type testModule struct {
   695  	ModuleBase
   696  	properties struct {
   697  		Rename string
   698  		Deps   []string
   699  		Id     string
   700  	}
   701  }
   702  
   703  func (m *testModule) DepsMutator(ctx BottomUpMutatorContext) {
   704  	if m.properties.Rename != "" {
   705  		ctx.Rename(m.properties.Rename)
   706  	}
   707  	for _, d := range m.properties.Deps {
   708  		ctx.AddDependency(ctx.Module(), nil, d)
   709  	}
   710  }
   711  
   712  func (m *testModule) GenerateAndroidBuildActions(ModuleContext) {
   713  }
   714  
   715  func renameMutator(ctx BottomUpMutatorContext) {
   716  	if m, ok := ctx.Module().(*testModule); ok {
   717  		if m.properties.Rename != "" {
   718  			ctx.Rename(m.properties.Rename)
   719  		}
   720  	}
   721  }
   722  
   723  func newTestModule() Module {
   724  	m := &testModule{}
   725  	m.AddProperties(&m.properties)
   726  	InitAndroidModule(m)
   727  	return m
   728  }