1// Copyright (C) 2019 The Android Open Source Project
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
15package aidl
16
17import (
18	"io/ioutil"
19	"os"
20	"path/filepath"
21	"strings"
22	"testing"
23
24	"github.com/google/blueprint"
25	"github.com/google/blueprint/proptools"
26
27	"android/soong/android"
28	"android/soong/cc"
29	"android/soong/java"
30)
31
32var buildDir string
33
34func setUp() {
35	var err error
36	buildDir, err = ioutil.TempDir("", "soong_aidl_test")
37	if err != nil {
38		panic(err)
39	}
40}
41
42func tearDown() {
43	os.RemoveAll(buildDir)
44}
45
46func TestMain(m *testing.M) {
47	run := func() int {
48		setUp()
49		defer tearDown()
50
51		return m.Run()
52	}
53
54	os.Exit(run())
55}
56
57type testCustomizer func(fs map[string][]byte, config android.Config)
58
59func withFiles(files map[string][]byte) testCustomizer {
60	return func(fs map[string][]byte, config android.Config) {
61		for k, v := range files {
62			fs[k] = v
63		}
64	}
65}
66
67func setReleaseEnv() testCustomizer {
68	return func(_ map[string][]byte, config android.Config) {
69		config.TestProductVariables.Platform_sdk_codename = proptools.StringPtr("REL")
70		config.TestProductVariables.Platform_sdk_final = proptools.BoolPtr(true)
71	}
72}
73
74func _testAidl(t *testing.T, bp string, customizers ...testCustomizer) (*android.TestContext, android.Config) {
75	t.Helper()
76
77	bp = bp + java.GatherRequiredDepsForTest()
78	bp = bp + cc.GatherRequiredDepsForTest(android.Android)
79	bp = bp + `
80		java_defaults {
81			name: "aidl-java-module-defaults",
82		}
83		cc_defaults {
84			name: "aidl-cpp-module-defaults",
85		}
86		cc_library {
87			name: "libbinder",
88		}
89		cc_library {
90			name: "libutils",
91		}
92		cc_library {
93			name: "libcutils",
94		}
95		cc_library {
96			name: "libbinder_ndk",
97		}
98		ndk_library {
99			name: "libbinder_ndk",
100			symbol_file: "libbinder_ndk.map.txt",
101			first_version: "29",
102		}
103		aidl_interfaces_metadata {
104			name: "aidl_metadata_json",
105		}
106	`
107	fs := map[string][]byte{}
108
109	cc.GatherRequiredFilesForTest(fs)
110
111	for _, c := range customizers {
112		// The fs now needs to be populated before creating the config, call customizers twice
113		// for now, once to get any fs changes, and later after the config was created to
114		// set product variables or targets.
115		tempConfig := android.TestArchConfig(buildDir, nil, bp, fs)
116		c(fs, tempConfig)
117	}
118
119	config := android.TestArchConfig(buildDir, nil, bp, fs)
120
121	// To keep tests stable, fix Platform_sdk_codename and Platform_sdk_final
122	// Use setReleaseEnv() to test release version
123	config.TestProductVariables.Platform_sdk_codename = proptools.StringPtr("Q")
124	config.TestProductVariables.Platform_sdk_final = proptools.BoolPtr(false)
125
126	for _, c := range customizers {
127		// The fs now needs to be populated before creating the config, call customizers twice
128		// for now, earlier to get any fs changes, and now after the config was created to
129		// set product variables or targets.
130		tempFS := map[string][]byte{}
131		c(tempFS, config)
132	}
133
134	ctx := android.NewTestArchContext()
135	cc.RegisterRequiredBuildComponentsForTest(ctx)
136	ctx.RegisterModuleType("aidl_interface", aidlInterfaceFactory)
137	ctx.RegisterModuleType("aidl_interfaces_metadata", aidlInterfacesMetadataSingletonFactory)
138	ctx.RegisterModuleType("android_app", java.AndroidAppFactory)
139	ctx.RegisterModuleType("java_defaults", func() android.Module {
140		return java.DefaultsFactory()
141	})
142	ctx.RegisterModuleType("java_library_static", java.LibraryStaticFactory)
143	ctx.RegisterModuleType("java_library", java.LibraryFactory)
144	ctx.RegisterModuleType("java_system_modules", java.SystemModulesFactory)
145
146	ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
147	ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators)
148	ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
149		ctx.BottomUp("checkUnstableModule", checkUnstableModuleMutator).Parallel()
150		ctx.BottomUp("checkDuplicatedVersions", checkDuplicatedVersions).Parallel()
151	})
152	ctx.Register(config)
153
154	return ctx, config
155}
156
157func testAidl(t *testing.T, bp string, customizers ...testCustomizer) (*android.TestContext, android.Config) {
158	t.Helper()
159	ctx, config := _testAidl(t, bp, customizers...)
160	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
161	android.FailIfErrored(t, errs)
162	_, errs = ctx.PrepareBuildActions(config)
163	android.FailIfErrored(t, errs)
164	return ctx, config
165}
166
167func testAidlError(t *testing.T, pattern, bp string, customizers ...testCustomizer) {
168	t.Helper()
169	ctx, config := _testAidl(t, bp, customizers...)
170	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
171	if len(errs) > 0 {
172		android.FailIfNoMatchingErrors(t, pattern, errs)
173		return
174	}
175	_, errs = ctx.PrepareBuildActions(config)
176	if len(errs) > 0 {
177		android.FailIfNoMatchingErrors(t, pattern, errs)
178		return
179	}
180	t.Fatalf("missing expected error %q (0 errors are returned)", pattern)
181}
182
183// asserts that there are expected module regardless of variants
184func assertModulesExists(t *testing.T, ctx *android.TestContext, names ...string) {
185	missing := []string{}
186	for _, name := range names {
187		variants := ctx.ModuleVariantsForTests(name)
188		if len(variants) == 0 {
189			missing = append(missing, name)
190		}
191	}
192	if len(missing) > 0 {
193		// find all the modules that do exist
194		allModuleNames := make(map[string]bool)
195		ctx.VisitAllModules(func(m blueprint.Module) {
196			allModuleNames[ctx.ModuleName(m)] = true
197		})
198		t.Errorf("expected modules(%v) not found. all modules: %v", missing, android.SortedStringKeys(allModuleNames))
199	}
200}
201
202// Vintf module must have versions in release version
203func TestVintfWithoutVersionInRelease(t *testing.T) {
204	vintfWithoutVersionBp := `
205	aidl_interface {
206		name: "foo",
207		stability: "vintf",
208		srcs: [
209			"IFoo.aidl",
210		],
211	}`
212	expectedError := `module "foo_interface": versions: must be set \(need to be frozen\) when "unstable" is false, PLATFORM_VERSION_CODENAME is REL, and "owner" property is missing.`
213	testAidlError(t, expectedError, vintfWithoutVersionBp, setReleaseEnv())
214
215	ctx, _ := testAidl(t, vintfWithoutVersionBp)
216	assertModulesExists(t, ctx, "foo-java", "foo-cpp", "foo-ndk", "foo-ndk_platform")
217}
218
219// Check if using unstable version in release cause an error.
220func TestUnstableVersionUsageInRelease(t *testing.T) {
221	unstableVersionUsageInJavaBp := `
222	aidl_interface {
223		name: "foo",
224		versions: [
225			"1",
226		],
227		srcs: [
228			"IFoo.aidl",
229		],
230	}
231	java_library {
232		name: "bar",
233		libs: ["foo-unstable-java"],
234	}`
235
236	expectedError := `unstable-java is disallowed in release version because it is unstable.`
237	testAidlError(t, expectedError, unstableVersionUsageInJavaBp, setReleaseEnv(), withFiles(map[string][]byte{
238		"aidl_api/foo/1/foo.1.aidl": nil,
239	}))
240
241	testAidl(t, unstableVersionUsageInJavaBp, withFiles(map[string][]byte{
242		"aidl_api/foo/1/foo.1.aidl": nil,
243	}))
244
245	// A stable version can be used in release version
246	stableVersionUsageInJavaBp := `
247	aidl_interface {
248		name: "foo",
249		versions: [
250			"1",
251		],
252		srcs: [
253			"IFoo.aidl",
254		],
255	}
256	java_library {
257		name: "bar",
258		libs: ["foo-java"],
259	}`
260
261	testAidl(t, stableVersionUsageInJavaBp, setReleaseEnv(), withFiles(map[string][]byte{
262		"aidl_api/foo/1/foo.1.aidl": nil,
263	}))
264
265	testAidl(t, stableVersionUsageInJavaBp, withFiles(map[string][]byte{
266		"aidl_api/foo/1/foo.1.aidl": nil,
267	}))
268}
269
270// The module which has never been frozen and is not "unstable" is not allowed in release version.
271func TestNonVersionedModuleUsageInRelease(t *testing.T) {
272	nonVersionedModuleUsageInJavaBp := `
273	aidl_interface {
274		name: "foo",
275		srcs: [
276			"IFoo.aidl",
277		],
278	}
279
280	java_library {
281		name: "bar",
282		libs: ["foo-java"],
283	}`
284
285	expectedError := `"foo_interface": versions: must be set \(need to be frozen\) when "unstable" is false, PLATFORM_VERSION_CODENAME is REL, and "owner" property is missing.`
286	testAidlError(t, expectedError, nonVersionedModuleUsageInJavaBp, setReleaseEnv())
287	testAidl(t, nonVersionedModuleUsageInJavaBp)
288
289	nonVersionedUnstableModuleUsageInJavaBp := `
290	aidl_interface {
291		name: "foo",
292		srcs: [
293			"IFoo.aidl",
294		],
295		unstable: true,
296	}
297
298	java_library {
299		name: "bar",
300		libs: ["foo-java"],
301	}`
302
303	testAidl(t, nonVersionedUnstableModuleUsageInJavaBp, setReleaseEnv())
304	testAidl(t, nonVersionedUnstableModuleUsageInJavaBp)
305}
306
307func TestUnstableModules(t *testing.T) {
308	testAidlError(t, `module "foo_interface": stability: must be empty when "unstable" is true`, `
309		aidl_interface {
310			name: "foo",
311			stability: "vintf",
312			unstable: true,
313			srcs: [
314				"IFoo.aidl",
315			],
316		}
317	`)
318
319	testAidlError(t, `module "foo_interface": versions: cannot have versions for an unstable interface`, `
320		aidl_interface {
321			name: "foo",
322			versions: [
323				"1",
324			],
325			unstable: true,
326			srcs: [
327				"IFoo.aidl",
328			],
329		}
330	`)
331
332	ctx, _ := testAidl(t, `
333		aidl_interface {
334			name: "foo",
335			unstable: true,
336			srcs: [
337				"IFoo.aidl",
338			],
339		}
340	`)
341
342	assertModulesExists(t, ctx, "foo-java", "foo-cpp", "foo-ndk", "foo-ndk_platform")
343}
344
345func TestCreatesModulesWithNoVersions(t *testing.T) {
346	ctx, _ := testAidl(t, `
347		aidl_interface {
348			name: "foo",
349			srcs: [
350				"IFoo.aidl",
351			],
352		}
353	`)
354
355	assertModulesExists(t, ctx, "foo-java", "foo-cpp", "foo-ndk", "foo-ndk_platform")
356}
357
358func TestCreatesModulesWithFrozenVersions(t *testing.T) {
359	// Each version should be under aidl_api/<name>/<ver>
360	testAidlError(t, `aidl_api/foo/1`, `
361		aidl_interface {
362			name: "foo",
363			srcs: [
364				"IFoo.aidl",
365			],
366			versions: [
367				"1",
368			],
369		}
370	`)
371
372	ctx, _ := testAidl(t, `
373		aidl_interface {
374			name: "foo",
375			srcs: [
376				"IFoo.aidl",
377			],
378			versions: [
379				"1",
380			],
381		}
382	`, withFiles(map[string][]byte{
383		"aidl_api/foo/1/foo.1.aidl": nil,
384	}))
385
386	// For alias for the latest frozen version (=1)
387	assertModulesExists(t, ctx, "foo-java", "foo-cpp", "foo-ndk", "foo-ndk_platform")
388
389	// For frozen version "1"
390	// Note that it is not yet implemented to generate native modules for latest frozen version
391	assertModulesExists(t, ctx, "foo-V1-java")
392
393	// For ToT (current)
394	assertModulesExists(t, ctx, "foo-unstable-java", "foo-unstable-cpp", "foo-unstable-ndk", "foo-unstable-ndk_platform")
395}
396
397const (
398	androidVariant = "android_common"
399	nativeVariant  = "android_arm_armv7-a-neon_shared"
400)
401
402func TestNativeOutputIsAlwaysVersioned(t *testing.T) {
403	var ctx *android.TestContext
404	assertOutput := func(moduleName, variant, outputFilename string) {
405		t.Helper()
406		producer, ok := ctx.ModuleForTests(moduleName, variant).Module().(android.OutputFileProducer)
407		if !ok {
408			t.Errorf("%s(%s): should be OutputFileProducer.", moduleName, variant)
409		}
410		paths, err := producer.OutputFiles("")
411		if err != nil {
412			t.Errorf("%s(%s): failed to get OutputFiles: %v", moduleName, variant, err)
413		}
414		if len(paths) != 1 || paths[0].Base() != outputFilename {
415			t.Errorf("%s(%s): expected output %q, but got %v", moduleName, variant, outputFilename, paths)
416		}
417	}
418
419	// No versions
420	ctx, _ = testAidl(t, `
421		aidl_interface {
422			name: "foo",
423			srcs: [
424				"IFoo.aidl",
425			],
426		}
427	`)
428
429	assertOutput("foo-java", androidVariant, "foo-java.jar")
430	assertOutput("foo-cpp", nativeVariant, "foo-V1-cpp.so")
431
432	// With versions: "1", "2"
433	ctx, _ = testAidl(t, `
434		aidl_interface {
435			name: "foo",
436			srcs: [
437				"IFoo.aidl",
438			],
439			versions: [
440				"1", "2",
441			],
442		}
443	`, withFiles(map[string][]byte{
444		"aidl_api/foo/1/foo.1.aidl": nil,
445		"aidl_api/foo/2/foo.2.aidl": nil,
446	}))
447
448	// alias for the latest frozen version (=2)
449	assertOutput("foo-java", androidVariant, "foo-java.jar")
450	assertOutput("foo-cpp", nativeVariant, "foo-V2-cpp.so")
451
452	// frozen "1"
453	assertOutput("foo-V1-java", androidVariant, "foo-V1-java.jar")
454	assertOutput("foo-V1-cpp", nativeVariant, "foo-V1-cpp.so")
455
456	// tot
457	assertOutput("foo-unstable-java", androidVariant, "foo-unstable-java.jar")
458	assertOutput("foo-unstable-cpp", nativeVariant, "foo-V3-cpp.so")
459
460	// skip ndk/ndk_platform since they follow the same rule with cpp
461}
462
463func TestGenLogForNativeBackendRequiresJson(t *testing.T) {
464	testAidlError(t, `"foo-cpp" depends on .*"libjsoncpp"`, `
465		aidl_interface {
466			name: "foo",
467			srcs: [
468				"IFoo.aidl",
469			],
470			backend: {
471				cpp: {
472					gen_log: true,
473				},
474			},
475		}
476	`)
477	testAidl(t, `
478		aidl_interface {
479			name: "foo",
480			srcs: [
481				"IFoo.aidl",
482			],
483			backend: {
484				cpp: {
485					gen_log: true,
486				},
487			},
488		}
489		cc_library {
490			name: "libjsoncpp",
491		}
492	`)
493}
494
495func TestImports(t *testing.T) {
496	testAidlError(t, `Import does not exist:`, `
497		aidl_interface {
498			name: "foo",
499			srcs: [
500				"IFoo.aidl",
501			],
502			imports: [
503				"bar",
504			]
505		}
506	`)
507
508	testAidlError(t, `backend.java.enabled: Java backend not enabled in the imported AIDL interface "bar"`, `
509		aidl_interface {
510			name: "foo",
511			srcs: [
512				"IFoo.aidl",
513			],
514			imports: [
515				"bar",
516			]
517		}
518		aidl_interface {
519			name: "bar",
520			srcs: [
521				"IBar.aidl",
522			],
523			backend: {
524				java: {
525					enabled: false,
526				},
527			},
528		}
529	`)
530
531	testAidlError(t, `backend.cpp.enabled: C\+\+ backend not enabled in the imported AIDL interface "bar"`, `
532		aidl_interface {
533			name: "foo",
534			srcs: [
535				"IFoo.aidl",
536			],
537			imports: [
538				"bar",
539			]
540		}
541		aidl_interface {
542			name: "bar",
543			srcs: [
544				"IBar.aidl",
545			],
546			backend: {
547				cpp: {
548					enabled: false,
549				},
550			},
551		}
552	`)
553
554	ctx, _ := testAidl(t, `
555		aidl_interface {
556			name: "foo",
557			srcs: [
558				"IFoo.aidl",
559			],
560			imports: [
561				"bar",
562			]
563		}
564		aidl_interface {
565			name: "bar",
566			srcs: [
567				"IBar.aidl",
568			],
569		}
570	`)
571
572	ldRule := ctx.ModuleForTests("foo-cpp", nativeVariant).Rule("ld")
573	libFlags := ldRule.Args["libFlags"]
574	libBar := filepath.Join("bar-cpp", nativeVariant, "bar-V1-cpp.so")
575	if !strings.Contains(libFlags, libBar) {
576		t.Errorf("%q is not found in %q", libBar, libFlags)
577	}
578}
579
580func TestDuplicatedVersions(t *testing.T) {
581	// foo depends on myiface-ndk (v2) via direct dep and also on
582	// myiface-V1-ndk via indirect dep. This should be prohibited.
583	testAidlError(t, `multiple versions of aidl_interface myiface \(backend:ndk\) are used`, `
584		aidl_interface {
585			name: "myiface",
586			srcs: ["IFoo.aidl"],
587			versions: ["1", "2"],
588		}
589
590		cc_library {
591			name: "foo",
592			shared_libs: ["myiface-ndk", "bar"],
593		}
594
595		cc_library {
596			name: "bar",
597			shared_libs: ["myiface-V1-ndk"],
598		}
599
600	`, withFiles(map[string][]byte{
601		"aidl_api/myiface/1/myiface.1.aidl": nil,
602		"aidl_api/myiface/1/.hash":          nil,
603		"aidl_api/myiface/2/myiface.2.aidl": nil,
604		"aidl_api/myiface/2/.hash":          nil,
605	}))
606}
607