From 063ec003f98a1cb45ddbda607dd41563d204f85d Mon Sep 17 00:00:00 2001 From: Jihoon Kang Date: Wed, 28 Jun 2023 01:16:23 +0000 Subject: Add current api check as validation for from-text stub generation Currently, there is no build action ensuring that the API text files are up to date, unless a user runs `m checkapi` or `m update-api`. This means that the user must run `m update-api` after making a change that modifies api surface(s), so that the API text file reflects the local change. This adds additional layer of action to developers, and it is not guaranteed that the developer will always run `m update-api` after making an api surface-affecting changes. To prevent such mistake, this change adds droidstub-level api check as validation for from-text stub generation. With this change, the build will fail if the API text file is not up to date and the user must run `m update-api` when making api surface-affecting local changes. The validation is done by adding all droidstubs modules associated with the java_api_contributions passed to java_api_library via `api_contributions` as dependency and setting the current api timestamp files as the validations for the from-text stubs generating build rule. The full api surface libraries will not run the validations to avoid circular dependency. However, all java_sdk_library generated java_api_library modules will run validations, mapped to the droidstubs in the same api domaion. If the user sets the environment variable `DISABLE_STUB_VALIDATION=true`, validation actions are not run. Validation actions run by default. Test: m nothing --build-from-text-stub and run ninja query to verify `check_current_api.timestamp`s are listed as validation \ DISABLE_STUB_VALIDATION=true m nothing --build-from-text-stub and run ninja query to verify that validation actions are not added Bug: 288624417 Change-Id: I329e6438fe8f3ac30d8c6a971d57853ed6b0d150 --- java/java_test.go | 216 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 166 insertions(+), 50 deletions(-) (limited to 'java/java_test.go') diff --git a/java/java_test.go b/java/java_test.go index 6b8b735f7..c4fc55bc4 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -1847,9 +1847,17 @@ func TestDeviceBinaryWrapperGeneration(t *testing.T) { } func TestJavaApiContributionEmptyApiFile(t *testing.T) { - testJavaError(t, + android.GroupFixturePreparers( + prepareForJavaTest, + android.FixtureMergeEnv( + map[string]string{ + "DISABLE_STUB_VALIDATION": "true", + }, + ), + ).ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern( "Error: foo has an empty api file.", - `java_api_contribution { + )).RunTestWithBp(t, ` + java_api_contribution { name: "foo", } java_api_library { @@ -1874,7 +1882,20 @@ func TestJavaApiLibraryAndProviderLink(t *testing.T) { api_surface: "public", } ` - ctx, _ := testJavaWithFS(t, ` + ctx := android.GroupFixturePreparers( + prepareForJavaTest, + android.FixtureMergeMockFs( + map[string][]byte{ + "a/Android.bp": []byte(provider_bp_a), + "b/Android.bp": []byte(provider_bp_b), + }, + ), + android.FixtureMergeEnv( + map[string]string{ + "DISABLE_STUB_VALIDATION": "true", + }, + ), + ).RunTestWithBp(t, ` java_api_library { name: "bar1", api_surface: "public", @@ -1886,11 +1907,7 @@ func TestJavaApiLibraryAndProviderLink(t *testing.T) { api_surface: "system", api_contributions: ["foo1", "foo2"], } - `, - map[string][]byte{ - "a/Android.bp": []byte(provider_bp_a), - "b/Android.bp": []byte(provider_bp_b), - }) + `) testcases := []struct { moduleName string @@ -1944,7 +1961,22 @@ func TestJavaApiLibraryAndDefaultsLink(t *testing.T) { api_surface: "system", } ` - ctx, _ := testJavaWithFS(t, ` + ctx := android.GroupFixturePreparers( + prepareForJavaTest, + android.FixtureMergeMockFs( + map[string][]byte{ + "a/Android.bp": []byte(provider_bp_a), + "b/Android.bp": []byte(provider_bp_b), + "c/Android.bp": []byte(provider_bp_c), + "d/Android.bp": []byte(provider_bp_d), + }, + ), + android.FixtureMergeEnv( + map[string]string{ + "DISABLE_STUB_VALIDATION": "true", + }, + ), + ).RunTestWithBp(t, ` java_defaults { name: "baz1", api_surface: "public", @@ -1975,13 +2007,7 @@ func TestJavaApiLibraryAndDefaultsLink(t *testing.T) { defaults:["baz1", "baz2"], api_contributions: ["foo4"], } - `, - map[string][]byte{ - "a/Android.bp": []byte(provider_bp_a), - "b/Android.bp": []byte(provider_bp_b), - "c/Android.bp": []byte(provider_bp_c), - "d/Android.bp": []byte(provider_bp_d), - }) + `) testcases := []struct { moduleName string @@ -2026,7 +2052,20 @@ func TestJavaApiLibraryJarGeneration(t *testing.T) { api_surface: "public", } ` - ctx, _ := testJavaWithFS(t, ` + ctx := android.GroupFixturePreparers( + prepareForJavaTest, + android.FixtureMergeMockFs( + map[string][]byte{ + "a/Android.bp": []byte(provider_bp_a), + "b/Android.bp": []byte(provider_bp_b), + }, + ), + android.FixtureMergeEnv( + map[string]string{ + "DISABLE_STUB_VALIDATION": "true", + }, + ), + ).RunTestWithBp(t, ` java_api_library { name: "bar1", api_surface: "public", @@ -2038,11 +2077,7 @@ func TestJavaApiLibraryJarGeneration(t *testing.T) { api_surface: "system", api_contributions: ["foo1", "foo2"], } - `, - map[string][]byte{ - "a/Android.bp": []byte(provider_bp_a), - "b/Android.bp": []byte(provider_bp_b), - }) + `) testcases := []struct { moduleName string @@ -2094,7 +2129,24 @@ func TestJavaApiLibraryLibsLink(t *testing.T) { } ` - ctx, _ := testJavaWithFS(t, ` + ctx := android.GroupFixturePreparers( + prepareForJavaTest, + android.FixtureMergeMockFs( + map[string][]byte{ + "a/Android.bp": []byte(provider_bp_a), + "b/Android.bp": []byte(provider_bp_b), + "c/Android.bp": []byte(lib_bp_a), + "c/Lib.java": {}, + "d/Android.bp": []byte(lib_bp_b), + "d/Lib.java": {}, + }, + ), + android.FixtureMergeEnv( + map[string]string{ + "DISABLE_STUB_VALIDATION": "true", + }, + ), + ).RunTestWithBp(t, ` java_api_library { name: "bar1", api_surface: "public", @@ -2108,15 +2160,7 @@ func TestJavaApiLibraryLibsLink(t *testing.T) { api_contributions: ["foo1", "foo2"], libs: ["lib1", "lib2", "bar1"], } - `, - map[string][]byte{ - "a/Android.bp": []byte(provider_bp_a), - "b/Android.bp": []byte(provider_bp_b), - "c/Android.bp": []byte(lib_bp_a), - "c/Lib.java": {}, - "d/Android.bp": []byte(lib_bp_b), - "d/Lib.java": {}, - }) + `) testcases := []struct { moduleName string @@ -2171,7 +2215,24 @@ func TestJavaApiLibraryStaticLibsLink(t *testing.T) { } ` - ctx, _ := testJavaWithFS(t, ` + ctx := android.GroupFixturePreparers( + prepareForJavaTest, + android.FixtureMergeMockFs( + map[string][]byte{ + "a/Android.bp": []byte(provider_bp_a), + "b/Android.bp": []byte(provider_bp_b), + "c/Android.bp": []byte(lib_bp_a), + "c/Lib.java": {}, + "d/Android.bp": []byte(lib_bp_b), + "d/Lib.java": {}, + }, + ), + android.FixtureMergeEnv( + map[string]string{ + "DISABLE_STUB_VALIDATION": "true", + }, + ), + ).RunTestWithBp(t, ` java_api_library { name: "bar1", api_surface: "public", @@ -2185,15 +2246,7 @@ func TestJavaApiLibraryStaticLibsLink(t *testing.T) { api_contributions: ["foo1", "foo2"], static_libs: ["lib1", "lib2", "bar1"], } - `, - map[string][]byte{ - "a/Android.bp": []byte(provider_bp_a), - "b/Android.bp": []byte(provider_bp_b), - "c/Android.bp": []byte(lib_bp_a), - "c/Lib.java": {}, - "d/Android.bp": []byte(lib_bp_b), - "d/Lib.java": {}, - }) + `) testcases := []struct { moduleName string @@ -2242,19 +2295,28 @@ func TestJavaApiLibraryFullApiSurfaceStub(t *testing.T) { } ` - ctx, _ := testJavaWithFS(t, ` + ctx := android.GroupFixturePreparers( + prepareForJavaTest, + android.FixtureMergeMockFs( + map[string][]byte{ + "a/Android.bp": []byte(provider_bp_a), + "b/Android.bp": []byte(provider_bp_b), + "c/Android.bp": []byte(lib_bp_a), + }, + ), + android.FixtureMergeEnv( + map[string]string{ + "DISABLE_STUB_VALIDATION": "true", + }, + ), + ).RunTestWithBp(t, ` java_api_library { name: "bar1", api_surface: "public", api_contributions: ["foo1"], full_api_surface_stub: "lib1", } - `, - map[string][]byte{ - "a/Android.bp": []byte(provider_bp_a), - "b/Android.bp": []byte(provider_bp_b), - "c/Android.bp": []byte(lib_bp_a), - }) + `) m := ctx.ModuleForTests("bar1", "android_common") manifest := m.Output("metalava.sbox.textproto") @@ -2402,7 +2464,14 @@ func TestHeadersOnly(t *testing.T) { } func TestJavaApiContributionImport(t *testing.T) { - ctx, _ := testJava(t, ` + ctx := android.GroupFixturePreparers( + prepareForJavaTest, + android.FixtureMergeEnv( + map[string]string{ + "DISABLE_STUB_VALIDATION": "true", + }, + ), + ).RunTestWithBp(t, ` java_api_library { name: "foo", api_contributions: ["bar"], @@ -2483,3 +2552,50 @@ func TestSdkLibraryProvidesSystemModulesToApiLibrary(t *testing.T) { classPathFlag := "--classpath __SBOX_SANDBOX_DIR__/out/.intermediates/bar/android_common/turbine-combined/bar.jar" android.AssertStringDoesContain(t, "command expected to contain classpath flag", manifestCommand, classPathFlag) } + +func TestApiLibraryDroidstubsDependency(t *testing.T) { + result := android.GroupFixturePreparers( + prepareForJavaTest, + PrepareForTestWithJavaSdkLibraryFiles, + FixtureWithLastReleaseApis("foo"), + android.FixtureModifyConfig(func(config android.Config) { + config.SetApiLibraries([]string{"foo"}) + }), + android.FixtureMergeMockFs( + map[string][]byte{ + "A.java": nil, + }, + ), + ).RunTestWithBp(t, ` + java_api_library { + name: "foo", + api_contributions: [ + "api-stubs-docs-non-updatable.api.contribution", + ], + enable_validation: true, + } + java_api_library { + name: "bar", + api_contributions: [ + "api-stubs-docs-non-updatable.api.contribution", + ], + enable_validation: false, + } + `) + + currentApiTimestampPath := "api-stubs-docs-non-updatable/android_common/metalava/check_current_api.timestamp" + foo := result.ModuleForTests("foo", "android_common").Module().(*ApiLibrary) + fooValidationPathsString := strings.Join(foo.validationPaths.Strings(), " ") + bar := result.ModuleForTests("bar", "android_common").Module().(*ApiLibrary) + barValidationPathsString := strings.Join(bar.validationPaths.Strings(), " ") + android.AssertStringDoesContain(t, + "Module expected to have validation", + fooValidationPathsString, + currentApiTimestampPath, + ) + android.AssertStringDoesNotContain(t, + "Module expected to not have validation", + barValidationPathsString, + currentApiTimestampPath, + ) +} -- cgit v1.2.3-59-g8ed1b