• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
14package android
15
16import (
17	"fmt"
18	"testing"
19
20	"android/soong/android/allowlists"
21	"android/soong/bazel"
22
23	"github.com/google/blueprint"
24	"github.com/google/blueprint/proptools"
25)
26
27func TestConvertAllModulesInPackage(t *testing.T) {
28	testCases := []struct {
29		prefixes   allowlists.Bp2BuildConfig
30		packageDir string
31	}{
32		{
33			prefixes: allowlists.Bp2BuildConfig{
34				"a": allowlists.Bp2BuildDefaultTrueRecursively,
35			},
36			packageDir: "a",
37		},
38		{
39			prefixes: allowlists.Bp2BuildConfig{
40				"a/b": allowlists.Bp2BuildDefaultTrueRecursively,
41			},
42			packageDir: "a/b",
43		},
44		{
45			prefixes: allowlists.Bp2BuildConfig{
46				"a/b":   allowlists.Bp2BuildDefaultTrueRecursively,
47				"a/b/c": allowlists.Bp2BuildDefaultTrueRecursively,
48			},
49			packageDir: "a/b",
50		},
51		{
52			prefixes: allowlists.Bp2BuildConfig{
53				"a":     allowlists.Bp2BuildDefaultTrueRecursively,
54				"d/e/f": allowlists.Bp2BuildDefaultTrueRecursively,
55			},
56			packageDir: "a/b",
57		},
58		{
59			prefixes: allowlists.Bp2BuildConfig{
60				"a":     allowlists.Bp2BuildDefaultFalse,
61				"a/b":   allowlists.Bp2BuildDefaultTrueRecursively,
62				"a/b/c": allowlists.Bp2BuildDefaultFalse,
63			},
64			packageDir: "a/b",
65		},
66		{
67			prefixes: allowlists.Bp2BuildConfig{
68				"a":     allowlists.Bp2BuildDefaultTrueRecursively,
69				"a/b":   allowlists.Bp2BuildDefaultFalse,
70				"a/b/c": allowlists.Bp2BuildDefaultTrueRecursively,
71			},
72			packageDir: "a",
73		},
74		{
75			prefixes: allowlists.Bp2BuildConfig{
76				"a":   allowlists.Bp2BuildDefaultFalseRecursively,
77				"a/b": allowlists.Bp2BuildDefaultTrue,
78			},
79			packageDir: "a/b",
80		},
81		{
82			prefixes: allowlists.Bp2BuildConfig{
83				"a":   allowlists.Bp2BuildDefaultFalseRecursively,
84				"a/b": allowlists.Bp2BuildDefaultTrueRecursively,
85			},
86			packageDir: "a/b/c",
87		},
88	}
89
90	for _, test := range testCases {
91		if ok, _ := bp2buildDefaultTrueRecursively(test.packageDir, test.prefixes); !ok {
92			t.Errorf("Expected to convert all modules in %s based on %v, but failed.", test.packageDir, test.prefixes)
93		}
94	}
95}
96
97func TestModuleOptIn(t *testing.T) {
98	testCases := []struct {
99		prefixes   allowlists.Bp2BuildConfig
100		packageDir string
101	}{
102		{
103			prefixes: allowlists.Bp2BuildConfig{
104				"a/b": allowlists.Bp2BuildDefaultFalse,
105			},
106			packageDir: "a/b",
107		},
108		{
109			prefixes: allowlists.Bp2BuildConfig{
110				"a":   allowlists.Bp2BuildDefaultFalse,
111				"a/b": allowlists.Bp2BuildDefaultTrueRecursively,
112			},
113			packageDir: "a",
114		},
115		{
116			prefixes: allowlists.Bp2BuildConfig{
117				"a/b": allowlists.Bp2BuildDefaultTrueRecursively,
118			},
119			packageDir: "a", // opt-in by default
120		},
121		{
122			prefixes: allowlists.Bp2BuildConfig{
123				"a/b/c": allowlists.Bp2BuildDefaultTrueRecursively,
124			},
125			packageDir: "a/b",
126		},
127		{
128			prefixes: allowlists.Bp2BuildConfig{
129				"a":     allowlists.Bp2BuildDefaultTrueRecursively,
130				"d/e/f": allowlists.Bp2BuildDefaultTrueRecursively,
131			},
132			packageDir: "foo/bar",
133		},
134		{
135			prefixes: allowlists.Bp2BuildConfig{
136				"a":     allowlists.Bp2BuildDefaultTrueRecursively,
137				"a/b":   allowlists.Bp2BuildDefaultFalse,
138				"a/b/c": allowlists.Bp2BuildDefaultTrueRecursively,
139			},
140			packageDir: "a/b",
141		},
142		{
143			prefixes: allowlists.Bp2BuildConfig{
144				"a":     allowlists.Bp2BuildDefaultFalse,
145				"a/b":   allowlists.Bp2BuildDefaultTrueRecursively,
146				"a/b/c": allowlists.Bp2BuildDefaultFalse,
147			},
148			packageDir: "a",
149		},
150		{
151			prefixes: allowlists.Bp2BuildConfig{
152				"a":   allowlists.Bp2BuildDefaultFalseRecursively,
153				"a/b": allowlists.Bp2BuildDefaultTrue,
154			},
155			packageDir: "a/b/c",
156		},
157		{
158			prefixes: allowlists.Bp2BuildConfig{
159				"a":   allowlists.Bp2BuildDefaultTrueRecursively,
160				"a/b": allowlists.Bp2BuildDefaultFalseRecursively,
161			},
162			packageDir: "a/b/c",
163		},
164	}
165
166	for _, test := range testCases {
167		if ok, _ := bp2buildDefaultTrueRecursively(test.packageDir, test.prefixes); ok {
168			t.Errorf("Expected to allow module opt-in in %s based on %v, but failed.", test.packageDir, test.prefixes)
169		}
170	}
171}
172
173type TestBazelModule struct {
174	bazel.TestModuleInfo
175	BazelModuleBase
176}
177
178var _ blueprint.Module = TestBazelModule{}
179
180func (m TestBazelModule) Name() string {
181	return m.TestModuleInfo.ModuleName
182}
183
184func (m TestBazelModule) GenerateBuildActions(blueprint.ModuleContext) {
185}
186
187type TestBazelConversionContext struct {
188	omc       bazel.OtherModuleTestContext
189	allowlist Bp2BuildConversionAllowlist
190	errors    []string
191}
192
193var _ bazelOtherModuleContext = &TestBazelConversionContext{}
194
195func (bcc *TestBazelConversionContext) OtherModuleType(m blueprint.Module) string {
196	return bcc.omc.OtherModuleType(m)
197}
198
199func (bcc *TestBazelConversionContext) OtherModuleName(m blueprint.Module) string {
200	return bcc.omc.OtherModuleName(m)
201}
202
203func (bcc *TestBazelConversionContext) OtherModuleDir(m blueprint.Module) string {
204	return bcc.omc.OtherModuleDir(m)
205}
206
207func (bcc *TestBazelConversionContext) ModuleErrorf(format string, args ...interface{}) {
208	bcc.errors = append(bcc.errors, fmt.Sprintf(format, args...))
209}
210
211func (bcc *TestBazelConversionContext) Config() Config {
212	return Config{
213		&config{
214			Bp2buildPackageConfig: bcc.allowlist,
215		},
216	}
217}
218
219var bazelableBazelModuleBase = BazelModuleBase{
220	bazelProperties: properties{
221		Bazel_module: bazelModuleProperties{
222			CanConvertToBazel: true,
223		},
224	},
225}
226
227func TestBp2BuildAllowlist(t *testing.T) {
228	testCases := []struct {
229		description    string
230		shouldConvert  bool
231		expectedErrors []string
232		module         TestBazelModule
233		allowlist      Bp2BuildConversionAllowlist
234	}{
235		{
236			description:   "allowlist enables module",
237			shouldConvert: true,
238			module: TestBazelModule{
239				TestModuleInfo: bazel.TestModuleInfo{
240					ModuleName: "foo",
241					Typ:        "rule1",
242					Dir:        "dir1",
243				},
244				BazelModuleBase: bazelableBazelModuleBase,
245			},
246			allowlist: Bp2BuildConversionAllowlist{
247				moduleAlwaysConvert: map[string]bool{
248					"foo": true,
249				},
250			},
251		},
252		{
253			description:    "module in name allowlist and type allowlist fails",
254			shouldConvert:  false,
255			expectedErrors: []string{"A module cannot be in moduleAlwaysConvert and also be in moduleTypeAlwaysConvert"},
256			module: TestBazelModule{
257				TestModuleInfo: bazel.TestModuleInfo{
258					ModuleName: "foo",
259					Typ:        "rule1",
260					Dir:        "dir1",
261				},
262				BazelModuleBase: bazelableBazelModuleBase,
263			},
264			allowlist: Bp2BuildConversionAllowlist{
265				moduleAlwaysConvert: map[string]bool{
266					"foo": true,
267				},
268				moduleTypeAlwaysConvert: map[string]bool{
269					"rule1": true,
270				},
271			},
272		},
273		{
274			description:    "module in allowlist and denylist fails",
275			shouldConvert:  false,
276			expectedErrors: []string{"a module cannot be in moduleDoNotConvert and also be in moduleAlwaysConvert"},
277			module: TestBazelModule{
278				TestModuleInfo: bazel.TestModuleInfo{
279					ModuleName: "foo",
280					Typ:        "rule1",
281					Dir:        "dir1",
282				},
283				BazelModuleBase: bazelableBazelModuleBase,
284			},
285			allowlist: Bp2BuildConversionAllowlist{
286				moduleAlwaysConvert: map[string]bool{
287					"foo": true,
288				},
289				moduleDoNotConvert: map[string]bool{
290					"foo": true,
291				},
292			},
293		},
294		{
295			description:    "module allowlist and enabled directory",
296			shouldConvert:  false,
297			expectedErrors: []string{"A module cannot be in a directory marked Bp2BuildDefaultTrue or Bp2BuildDefaultTrueRecursively and also be in moduleAlwaysConvert. Directory: 'existing/build/dir' Module: 'foo'"},
298			module: TestBazelModule{
299				TestModuleInfo: bazel.TestModuleInfo{
300					ModuleName: "foo",
301					Typ:        "rule1",
302					Dir:        "existing/build/dir",
303				},
304				BazelModuleBase: bazelableBazelModuleBase,
305			},
306			allowlist: Bp2BuildConversionAllowlist{
307				moduleAlwaysConvert: map[string]bool{
308					"foo": true,
309				},
310				defaultConfig: allowlists.Bp2BuildConfig{
311					"existing/build/dir": allowlists.Bp2BuildDefaultTrue,
312				},
313			},
314		},
315		{
316			description:    "module allowlist and enabled subdirectory",
317			shouldConvert:  false,
318			expectedErrors: []string{"A module cannot be in a directory marked Bp2BuildDefaultTrue or Bp2BuildDefaultTrueRecursively and also be in moduleAlwaysConvert. Directory: 'existing/build/dir' Module: 'foo'"},
319			module: TestBazelModule{
320				TestModuleInfo: bazel.TestModuleInfo{
321					ModuleName: "foo",
322					Typ:        "rule1",
323					Dir:        "existing/build/dir/subdir",
324				},
325				BazelModuleBase: bazelableBazelModuleBase,
326			},
327			allowlist: Bp2BuildConversionAllowlist{
328				moduleAlwaysConvert: map[string]bool{
329					"foo": true,
330				},
331				defaultConfig: allowlists.Bp2BuildConfig{
332					"existing/build/dir": allowlists.Bp2BuildDefaultTrueRecursively,
333				},
334			},
335		},
336		{
337			description:   "module enabled in unit test short-circuits other allowlists",
338			shouldConvert: true,
339			module: TestBazelModule{
340				TestModuleInfo: bazel.TestModuleInfo{
341					ModuleName: "foo",
342					Typ:        "rule1",
343					Dir:        ".",
344				},
345				BazelModuleBase: BazelModuleBase{
346					bazelProperties: properties{
347						Bazel_module: bazelModuleProperties{
348							CanConvertToBazel:  true,
349							Bp2build_available: proptools.BoolPtr(true),
350						},
351					},
352				},
353			},
354			allowlist: Bp2BuildConversionAllowlist{
355				moduleAlwaysConvert: map[string]bool{
356					"foo": true,
357				},
358				moduleDoNotConvert: map[string]bool{
359					"foo": true,
360				},
361			},
362		},
363	}
364
365	for _, test := range testCases {
366		t.Run(test.description, func(t *testing.T) {
367			bcc := &TestBazelConversionContext{
368				omc: bazel.OtherModuleTestContext{
369					Modules: []bazel.TestModuleInfo{
370						test.module.TestModuleInfo,
371					},
372				},
373				allowlist: test.allowlist,
374			}
375
376			shouldConvert := test.module.shouldConvertWithBp2build(bcc, test.module.TestModuleInfo)
377			if test.shouldConvert != shouldConvert {
378				t.Errorf("Module shouldConvert expected to be: %v, but was: %v", test.shouldConvert, shouldConvert)
379			}
380
381			errorsMatch := true
382			if len(test.expectedErrors) != len(bcc.errors) {
383				errorsMatch = false
384			} else {
385				for i, err := range test.expectedErrors {
386					if err != bcc.errors[i] {
387						errorsMatch = false
388					}
389				}
390			}
391			if !errorsMatch {
392				t.Errorf("Expected errors to be: %v, but were: %v", test.expectedErrors, bcc.errors)
393			}
394		})
395	}
396}
397
398func TestBp2buildAllowList(t *testing.T) {
399	allowlist := GetBp2BuildAllowList()
400	for k, v := range allowlists.Bp2buildDefaultConfig {
401		if allowlist.defaultConfig[k] != v {
402			t.Errorf("bp2build default config of %s: expected: %v, got: %v", k, v, allowlist.defaultConfig[k])
403		}
404	}
405	for k, v := range allowlists.Bp2buildKeepExistingBuildFile {
406		if allowlist.keepExistingBuildFile[k] != v {
407			t.Errorf("bp2build keep existing build file of %s: expected: %v, got: %v", k, v, allowlist.keepExistingBuildFile[k])
408		}
409	}
410	for _, k := range allowlists.Bp2buildModuleTypeAlwaysConvertList {
411		if !allowlist.moduleTypeAlwaysConvert[k] {
412			t.Errorf("bp2build module type always convert of %s: expected: true, got: %v", k, allowlist.moduleTypeAlwaysConvert[k])
413		}
414	}
415	for _, k := range allowlists.Bp2buildModuleDoNotConvertList {
416		if !allowlist.moduleDoNotConvert[k] {
417			t.Errorf("bp2build module do not convert of %s: expected: true, got: %v", k, allowlist.moduleDoNotConvert[k])
418		}
419	}
420}
421
422func TestShouldKeepExistingBuildFileForDir(t *testing.T) {
423	allowlist := NewBp2BuildAllowlist()
424	// entry "a/b2/c2" is moot because of its parent "a/b2"
425	allowlist.SetKeepExistingBuildFile(map[string]bool{"a": false, "a/b1": false, "a/b2": true, "a/b1/c1": true, "a/b2/c2": false})
426	truths := []string{"a", "a/b1", "a/b2", "a/b1/c1", "a/b2/c", "a/b2/c2", "a/b2/c2/d"}
427	falsities := []string{"a1", "a/b", "a/b1/c"}
428	for _, dir := range truths {
429		if !allowlist.ShouldKeepExistingBuildFileForDir(dir) {
430			t.Errorf("%s expected TRUE but was FALSE", dir)
431		}
432	}
433	for _, dir := range falsities {
434		if allowlist.ShouldKeepExistingBuildFileForDir(dir) {
435			t.Errorf("%s expected FALSE but was TRUE", dir)
436		}
437	}
438}
439