Merge "Move signing related options to a shared place" into main
diff --git a/core/release_config.mk b/core/release_config.mk
index 6428b0d..68dd876 100644
--- a/core/release_config.mk
+++ b/core/release_config.mk
@@ -82,28 +82,32 @@
)
FLAG_DECLARATION_FILES :=
-# If TARGET_RELEASE is set, fail if there is no matching release config
-# If it isn't set, no release config files will be included and all flags
-# will get their default values.
-ifneq ($(TARGET_RELEASE),)
+ifeq ($(TARGET_RELEASE),)
+ # We allow some internal paths to explicitly set TARGET_RELEASE to the
+ # empty string. For the most part, 'make' treats unset and empty string as
+ # the same. But the following line differentiates, and will only assign
+ # if the variable was completely unset.
+ TARGET_RELEASE ?= was_unset
+ ifeq ($(TARGET_RELEASE),was_unset)
+ $(error No release config set for target; please set TARGET_RELEASE, or if building on the command line use 'lunch <target>-<release>-<build_type>', where release is one of: $(_all_release_configs))
+ endif
+ # Instead of leaving this string empty, we want to default to a valid
+ # setting. Full builds coming through this path is a bug, but in case
+ # of such a bug, we want to at least get consistent, valid results.
+ TARGET_RELEASE = trunk_staging
+endif
+
ifeq ($(filter $(_all_release_configs), $(TARGET_RELEASE)),)
$(error No release config found for TARGET_RELEASE: $(TARGET_RELEASE). Available releases are: $(_all_release_configs))
-else
- # Choose flag files
- # Don't sort this, use it in the order they gave us.
- # Do allow duplicate entries, retaining only the first usage.
- flag_value_files :=
- $(foreach f,$(_all_release_configs.$(TARGET_RELEASE).FILES), \
- $(if $(filter $(f),$(flag_value_files)),,$(eval flag_value_files += $(f)))\
- )
endif
-else
-# Useful for finding scripts etc that aren't passing or setting TARGET_RELEASE
-ifneq ($(FAIL_IF_NO_RELEASE_CONFIG),)
- $(error FAIL_IF_NO_RELEASE_CONFIG was set and TARGET_RELEASE was not)
-endif
+
+# Choose flag files
+# Don't sort this, use it in the order they gave us.
+# Do allow duplicate entries, retaining only the first usage.
flag_value_files :=
-endif
+$(foreach f,$(_all_release_configs.$(TARGET_RELEASE).FILES), \
+ $(if $(filter $(f),$(flag_value_files)),,$(eval flag_value_files += $(f)))\
+)
# Unset variables so they can't use them
define declare-release-config
diff --git a/core/soong_cc_rust_prebuilt.mk b/core/soong_cc_rust_prebuilt.mk
index 143931b..94e1115 100644
--- a/core/soong_cc_rust_prebuilt.mk
+++ b/core/soong_cc_rust_prebuilt.mk
@@ -129,8 +129,13 @@
ifdef LOCAL_SHARED_LIBRARIES
my_shared_libraries := $(LOCAL_SHARED_LIBRARIES)
ifdef LOCAL_USE_VNDK
- my_shared_libraries := $(foreach l,$(my_shared_libraries),\
- $(if $(SPLIT_VENDOR.SHARED_LIBRARIES.$(l)),$(l).vendor,$(l)))
+ ifdef LOCAL_USE_VNDK_PRODUCT
+ my_shared_libraries := $(foreach l,$(my_shared_libraries),\
+ $(if $(SPLIT_PRODUCT.SHARED_LIBRARIES.$(l)),$(l).product,$(l)))
+ else
+ my_shared_libraries := $(foreach l,$(my_shared_libraries),\
+ $(if $(SPLIT_VENDOR.SHARED_LIBRARIES.$(l)),$(l).vendor,$(l)))
+ endif
endif
$(LOCAL_2ND_ARCH_VAR_PREFIX)$(my_prefix)DEPENDENCIES_ON_SHARED_LIBRARIES += \
$(my_register_name):$(LOCAL_INSTALLED_MODULE):$(subst $(space),$(comma),$(my_shared_libraries))
@@ -139,8 +144,13 @@
my_dylibs := $(LOCAL_DYLIB_LIBRARIES)
# Treat these as shared library dependencies for installation purposes.
ifdef LOCAL_USE_VNDK
- my_dylibs := $(foreach l,$(my_dylibs),\
- $(if $(SPLIT_VENDOR.SHARED_LIBRARIES.$(l)),$(l).vendor,$(l)))
+ ifdef LOCAL_USE_VNDK_PRODUCT
+ my_dylibs := $(foreach l,$(my_dylibs),\
+ $(if $(SPLIT_PRODUCT.SHARED_LIBRARIES.$(l)),$(l).product,$(l)))
+ else
+ my_dylibs := $(foreach l,$(my_dylibs),\
+ $(if $(SPLIT_VENDOR.SHARED_LIBRARIES.$(l)),$(l).vendor,$(l)))
+ endif
endif
$(LOCAL_2ND_ARCH_VAR_PREFIX)$(my_prefix)DEPENDENCIES_ON_SHARED_LIBRARIES += \
$(my_register_name):$(LOCAL_INSTALLED_MODULE):$(subst $(space),$(comma),$(my_dylibs))
diff --git a/target/product/base_system.mk b/target/product/base_system.mk
index e3ebaa3..69a2abf 100644
--- a/target/product/base_system.mk
+++ b/target/product/base_system.mk
@@ -53,7 +53,6 @@
com.android.btservices \
com.android.configinfrastructure \
com.android.conscrypt \
- com.android.crashrecovery \
com.android.devicelock \
com.android.extservices \
com.android.healthfitness \
diff --git a/target/product/default_art_config.mk b/target/product/default_art_config.mk
index 0324980..bc11fea 100644
--- a/target/product/default_art_config.mk
+++ b/target/product/default_art_config.mk
@@ -67,7 +67,6 @@
com.android.btservices:framework-bluetooth \
com.android.configinfrastructure:framework-configinfrastructure \
com.android.conscrypt:conscrypt \
- com.android.crashrecovery:framework-crashrecovery \
com.android.devicelock:framework-devicelock \
com.android.healthfitness:framework-healthfitness \
com.android.i18n:core-icu4j \
@@ -102,7 +101,6 @@
com.android.appsearch:service-appsearch \
com.android.art:service-art \
com.android.configinfrastructure:service-configinfrastructure \
- com.android.crashrecovery:service-crashrecovery \
com.android.healthfitness:service-healthfitness \
com.android.media:service-media-s \
com.android.ondevicepersonalization:service-ondevicepersonalization \
diff --git a/tools/aconfig/Android.bp b/tools/aconfig/Android.bp
index e2fadb0..1ad9053 100644
--- a/tools/aconfig/Android.bp
+++ b/tools/aconfig/Android.bp
@@ -58,7 +58,6 @@
"libaconfig_protos",
"libanyhow",
"libclap",
- "libitertools",
"libprotobuf",
"libserde",
"libserde_json",
diff --git a/tools/aconfig/Cargo.toml b/tools/aconfig/Cargo.toml
index 2edf4b8..941b30d 100644
--- a/tools/aconfig/Cargo.toml
+++ b/tools/aconfig/Cargo.toml
@@ -11,7 +11,6 @@
[dependencies]
anyhow = "1.0.69"
clap = { version = "4.1.8", features = ["derive"] }
-itertools = "0.10.5"
paste = "1.0.11"
protobuf = "3.2.0"
serde = { version = "1.0.152", features = ["derive"] }
diff --git a/tools/aconfig/src/codegen_java.rs b/tools/aconfig/src/codegen_java.rs
index 954eccc..05ee0d7 100644
--- a/tools/aconfig/src/codegen_java.rs
+++ b/tools/aconfig/src/codegen_java.rs
@@ -15,7 +15,6 @@
*/
use anyhow::Result;
-use itertools::Itertools;
use serde::Serialize;
use std::collections::BTreeSet;
use std::path::PathBuf;
@@ -35,18 +34,12 @@
{
let flag_elements: Vec<FlagElement> =
parsed_flags_iter.map(|pf| create_flag_element(package, pf)).collect();
- let namespace_set: BTreeSet<String> = flag_elements
- .iter()
- .unique_by(|f| &f.device_config_namespace)
- .map(|f| f.device_config_namespace.clone())
- .collect();
let properties_set: BTreeSet<String> =
flag_elements.iter().map(|fe| format_property_name(&fe.device_config_namespace)).collect();
let is_read_write = flag_elements.iter().any(|elem| elem.is_read_write);
let is_test_mode = codegen_mode == CodegenMode::Test;
let context = Context {
flag_elements,
- namespace_set,
is_test_mode,
is_read_write,
properties_set,
@@ -82,7 +75,6 @@
#[derive(Serialize)]
struct Context {
pub flag_elements: Vec<FlagElement>,
- pub namespace_set: BTreeSet<String>,
pub is_test_mode: bool,
pub is_read_write: bool,
pub properties_set: BTreeSet<String>,
@@ -297,31 +289,7 @@
import android.provider.DeviceConfig.Properties;
/** @hide */
public final class FeatureFlagsImpl implements FeatureFlags {
- private static boolean aconfig_test_is_cached = false;
- private static boolean disabledRw = false;
- private static boolean enabledRw = true;
-
-
- private void load_overrides_aconfig_test() {
- try {
- Properties properties = DeviceConfig.getProperties("aconfig_test");
- disabledRw =
- properties.getBoolean("com.android.aconfig.test.disabled_rw", false);
- enabledRw =
- properties.getBoolean("com.android.aconfig.test.enabled_rw", true);
- } catch (NullPointerException e) {
- throw new RuntimeException(
- "Cannot read value from namespace aconfig_test "
- + "from DeviceConfig. It could be that the code using flag "
- + "executed before SettingsProvider initialization. Please use "
- + "fixed read-only flag by adding is_fixed_read_only: true in "
- + "flag declaration.",
- e
- );
- }
- aconfig_test_is_cached = true;
- }
-
+ private Properties mPropertiesAconfigTest;
@Override
@UnsupportedAppUsage
public boolean disabledRo() {
@@ -330,10 +298,18 @@
@Override
@UnsupportedAppUsage
public boolean disabledRw() {
- if (!aconfig_test_is_cached) {
- load_overrides_aconfig_test();
+ if (mPropertiesAconfigTest == null) {
+ mPropertiesAconfigTest =
+ getProperties(
+ "aconfig_test",
+ "com.android.aconfig.test.disabled_rw"
+ );
}
- return disabledRw;
+ return mPropertiesAconfigTest
+ .getBoolean(
+ "com.android.aconfig.test.disabled_rw",
+ false
+ );
}
@Override
@UnsupportedAppUsage
@@ -348,10 +324,36 @@
@Override
@UnsupportedAppUsage
public boolean enabledRw() {
- if (!aconfig_test_is_cached) {
- load_overrides_aconfig_test();
+ if (mPropertiesAconfigTest == null) {
+ mPropertiesAconfigTest =
+ getProperties(
+ "aconfig_test",
+ "com.android.aconfig.test.enabled_rw"
+ );
}
- return enabledRw;
+ return mPropertiesAconfigTest
+ .getBoolean(
+ "com.android.aconfig.test.enabled_rw",
+ true
+ );
+ }
+ private Properties getProperties(
+ String namespace,
+ String flagName) {
+ Properties properties = null;
+ try {
+ properties = DeviceConfig.getProperties(namespace);
+ } catch (NullPointerException e) {
+ throw new RuntimeException(
+ "Cannot read value of flag " + flagName + " from DeviceConfig. "
+ + "It could be that the code using flag executed "
+ + "before SettingsProvider initialization. "
+ + "Please use fixed read-only flag by adding "
+ + "is_fixed_read_only: true in flag declaration.",
+ e
+ );
+ }
+ return properties;
}
}
"#;
diff --git a/tools/aconfig/templates/FeatureFlagsImpl.java.template b/tools/aconfig/templates/FeatureFlagsImpl.java.template
index 87d567c..ff089df 100644
--- a/tools/aconfig/templates/FeatureFlagsImpl.java.template
+++ b/tools/aconfig/templates/FeatureFlagsImpl.java.template
@@ -8,41 +8,10 @@
{{ endif }}
/** @hide */
public final class FeatureFlagsImpl implements FeatureFlags \{
-{{- if is_read_write }}
-{{- for namespace in namespace_set }}
- private static boolean {namespace}_is_cached = false;
-{{- endfor- }}
-
-{{ for flag in flag_elements }}
-{{- if flag.is_read_write }}
- private static boolean {flag.method_name} = {flag.default_value};
-{{- endif- }}
+{{ if is_read_write- }}
+{{ for properties in properties_set }}
+ private Properties {properties};
{{ endfor }}
-
-{{ for namespace in namespace_set }}
- private void load_overrides_{namespace}() \{
- try \{
- Properties properties = DeviceConfig.getProperties("{namespace}");
-
- {{- for flag in flag_elements }}
- {{- if flag.is_read_write }}
- {flag.method_name} =
- properties.getBoolean("{flag.device_config_flag}", {flag.default_value});
- {{- endif- }}
- {{ endfor }}
- } catch (NullPointerException e) \{
- throw new RuntimeException(
- "Cannot read value from namespace {namespace} "
- + "from DeviceConfig. It could be that the code using flag "
- + "executed before SettingsProvider initialization. Please use "
- + "fixed read-only flag by adding is_fixed_read_only: true in "
- + "flag declaration.",
- e
- );
- }
- {namespace}_is_cached = true;
- }
-{{ endfor- }}
{{ endif- }}
{{ for flag in flag_elements }}
@@ -50,15 +19,45 @@
@UnsupportedAppUsage
public boolean {flag.method_name}() \{
{{ -if flag.is_read_write }}
- if (!{flag.device_config_namespace}_is_cached) \{
- load_overrides_{flag.device_config_namespace}();
+ if ({flag.properties} == null) \{
+ {flag.properties} =
+ getProperties(
+ "{flag.device_config_namespace}",
+ "{flag.device_config_flag}"
+ );
}
- return {flag.method_name};
+ return {flag.properties}
+ .getBoolean(
+ "{flag.device_config_flag}",
+ {flag.default_value}
+ );
{{ else }}
return {flag.default_value};
{{ endif- }}
}
{{ endfor }}
+
+{{ -if is_read_write }}
+ private Properties getProperties(
+ String namespace,
+ String flagName) \{
+ Properties properties = null;
+ try \{
+ properties = DeviceConfig.getProperties(namespace);
+ } catch (NullPointerException e) \{
+ throw new RuntimeException(
+ "Cannot read value of flag " + flagName + " from DeviceConfig. "
+ + "It could be that the code using flag executed "
+ + "before SettingsProvider initialization. "
+ + "Please use fixed read-only flag by adding "
+ + "is_fixed_read_only: true in flag declaration.",
+ e
+ );
+ }
+
+ return properties;
+ }
+{{ endif- }}
}
{{ else }}
{#- Generate only stub if in test mode #}
@@ -71,6 +70,6 @@
throw new UnsupportedOperationException(
"Method is not implemented.");
}
-{{ endfor- }}
+{{ endfor }}
}
{{ endif }}
diff --git a/tools/finalization/environment.sh b/tools/finalization/environment.sh
index 9714ac4..d9c42c8 100755
--- a/tools/finalization/environment.sh
+++ b/tools/finalization/environment.sh
@@ -22,3 +22,5 @@
# 'sdk' - SDK/API is finalized
# 'rel' - branch is finalized, switched to REL
export FINAL_STATE='unfinalized'
+
+export BUILD_FROM_SOURCE_STUB=true
\ No newline at end of file
diff --git a/tools/metadata/Android.bp b/tools/metadata/Android.bp
new file mode 100644
index 0000000..b2fabec
--- /dev/null
+++ b/tools/metadata/Android.bp
@@ -0,0 +1,14 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+blueprint_go_binary {
+ name: "metadata",
+ deps: [
+ "soong-testing-test_spec_proto",
+ "golang-protobuf-proto",
+ ],
+ srcs: [
+ "generator.go",
+ ]
+}
\ No newline at end of file
diff --git a/tools/metadata/generator.go b/tools/metadata/generator.go
new file mode 100644
index 0000000..8e82f7f
--- /dev/null
+++ b/tools/metadata/generator.go
@@ -0,0 +1,169 @@
+package main
+
+import (
+ "flag"
+ "fmt"
+ "io"
+ "log"
+ "os"
+ "sort"
+ "strings"
+ "sync"
+
+ "android/soong/testing/test_spec_proto"
+ "google.golang.org/protobuf/proto"
+)
+
+type keyToLocksMap struct {
+ locks sync.Map
+}
+
+func (kl *keyToLocksMap) GetLockForKey(key string) *sync.Mutex {
+ mutex, _ := kl.locks.LoadOrStore(key, &sync.Mutex{})
+ return mutex.(*sync.Mutex)
+}
+
+func getSortedKeys(syncMap *sync.Map) []string {
+ var allKeys []string
+ syncMap.Range(
+ func(key, _ interface{}) bool {
+ allKeys = append(allKeys, key.(string))
+ return true
+ },
+ )
+
+ sort.Strings(allKeys)
+ return allKeys
+}
+
+func writeOutput(
+ outputFile string,
+ allMetadata []*test_spec_proto.TestSpec_OwnershipMetadata,
+) {
+ testSpec := &test_spec_proto.TestSpec{
+ OwnershipMetadataList: allMetadata,
+ }
+ data, err := proto.Marshal(testSpec)
+ if err != nil {
+ log.Fatal(err)
+ }
+ file, err := os.Create(outputFile)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer file.Close()
+
+ _, err = file.Write(data)
+ if err != nil {
+ log.Fatal(err)
+ }
+}
+
+func readFileToString(filePath string) string {
+ file, err := os.Open(filePath)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer file.Close()
+
+ data, err := io.ReadAll(file)
+ if err != nil {
+ log.Fatal(err)
+ }
+ return string(data)
+}
+
+func processProtobuf(
+ filePath string, ownershipMetadataMap *sync.Map, keyLocks *keyToLocksMap,
+ errCh chan error, wg *sync.WaitGroup,
+) {
+ defer wg.Done()
+
+ fileContent := strings.TrimRight(readFileToString(filePath), "\n")
+ testData := test_spec_proto.TestSpec{}
+ err := proto.Unmarshal([]byte(fileContent), &testData)
+ if err != nil {
+ errCh <- err
+ return
+ }
+
+ ownershipMetadata := testData.GetOwnershipMetadataList()
+ for _, metadata := range ownershipMetadata {
+ key := metadata.GetTargetName()
+ lock := keyLocks.GetLockForKey(key)
+ lock.Lock()
+
+ value, loaded := ownershipMetadataMap.LoadOrStore(
+ key, []*test_spec_proto.TestSpec_OwnershipMetadata{metadata},
+ )
+ if loaded {
+ existingMetadata := value.([]*test_spec_proto.TestSpec_OwnershipMetadata)
+ isDuplicate := false
+ for _, existing := range existingMetadata {
+ if metadata.GetTrendyTeamId() != existing.GetTrendyTeamId() {
+ errCh <- fmt.Errorf(
+ "Conflicting trendy team IDs found for %s at:\n%s with teamId"+
+ ": %s,\n%s with teamId: %s",
+ key,
+ metadata.GetPath(), metadata.GetTrendyTeamId(), existing.GetPath(),
+ existing.GetTrendyTeamId(),
+ )
+
+ lock.Unlock()
+ return
+ }
+ if metadata.GetTrendyTeamId() == existing.GetTrendyTeamId() && metadata.GetPath() == existing.GetPath() {
+ isDuplicate = true
+ break
+ }
+ }
+ if !isDuplicate {
+ existingMetadata = append(existingMetadata, metadata)
+ ownershipMetadataMap.Store(key, existingMetadata)
+ }
+ }
+
+ lock.Unlock()
+ }
+}
+
+func main() {
+ inputFile := flag.String("inputFile", "", "Input file path")
+ outputFile := flag.String("outputFile", "", "Output file path")
+ flag.Parse()
+
+ if *inputFile == "" || *outputFile == "" {
+ fmt.Println("Usage: metadata -inputFile <input file path> -outputFile <output file path>")
+ os.Exit(1)
+ }
+
+ inputFileData := strings.TrimRight(readFileToString(*inputFile), "\n")
+ filePaths := strings.Split(inputFileData, "\n")
+ ownershipMetadataMap := &sync.Map{}
+ keyLocks := &keyToLocksMap{}
+ errCh := make(chan error, len(filePaths))
+ var wg sync.WaitGroup
+
+ for _, filePath := range filePaths {
+ wg.Add(1)
+ go processProtobuf(filePath, ownershipMetadataMap, keyLocks, errCh, &wg)
+ }
+
+ wg.Wait()
+ close(errCh)
+
+ for err := range errCh {
+ log.Fatal(err)
+ }
+
+ allKeys := getSortedKeys(ownershipMetadataMap)
+ var allMetadata []*test_spec_proto.TestSpec_OwnershipMetadata
+
+ for _, key := range allKeys {
+ value, _ := ownershipMetadataMap.Load(key)
+ metadataList := value.([]*test_spec_proto.TestSpec_OwnershipMetadata)
+ allMetadata = append(allMetadata, metadataList...)
+ }
+
+ writeOutput(*outputFile, allMetadata)
+}
diff --git a/tools/metadata/go.mod b/tools/metadata/go.mod
new file mode 100644
index 0000000..e9d04b1
--- /dev/null
+++ b/tools/metadata/go.mod
@@ -0,0 +1,7 @@
+module android/soong/tools/metadata
+
+require google.golang.org/protobuf v0.0.0
+
+replace google.golang.org/protobuf v0.0.0 => ../../../external/golang-protobuf
+
+go 1.18
\ No newline at end of file
diff --git a/tools/metadata/go.work b/tools/metadata/go.work
new file mode 100644
index 0000000..23875da
--- /dev/null
+++ b/tools/metadata/go.work
@@ -0,0 +1,10 @@
+go 1.18
+
+use (
+ .
+ ../../../../external/golang-protobuf
+ ../../../soong/testing/test_spec_proto
+
+)
+
+replace google.golang.org/protobuf v0.0.0 => ../../../../external/golang-protobuf
diff --git a/tools/metadata/testdata/expectedOutputFile.txt b/tools/metadata/testdata/expectedOutputFile.txt
new file mode 100644
index 0000000..b0d382f
--- /dev/null
+++ b/tools/metadata/testdata/expectedOutputFile.txt
@@ -0,0 +1,22 @@
+
+.
+java-test-module-name-one
+Android.bp12345
+.
+java-test-module-name-six
+Android.bp12346
+.
+java-test-module-name-six
+Aqwerty.bp12346
+.
+java-test-module-name-six
+Apoiuyt.bp12346
+.
+java-test-module-name-two
+Android.bp12345
+.
+java-test-module-name-two
+Asdfghj.bp12345
+.
+java-test-module-name-two
+Azxcvbn.bp12345
\ No newline at end of file
diff --git a/tools/metadata/testdata/file1.txt b/tools/metadata/testdata/file1.txt
new file mode 100644
index 0000000..81beed0
--- /dev/null
+++ b/tools/metadata/testdata/file1.txt
@@ -0,0 +1,13 @@
+
+.
+java-test-module-name-one
+Android.bp12345
+.
+java-test-module-name-two
+Android.bp12345
+.
+java-test-module-name-two
+Asdfghj.bp12345
+.
+java-test-module-name-two
+Azxcvbn.bp12345
diff --git a/tools/metadata/testdata/file2.txt b/tools/metadata/testdata/file2.txt
new file mode 100644
index 0000000..32a753f
--- /dev/null
+++ b/tools/metadata/testdata/file2.txt
@@ -0,0 +1,25 @@
+
+.
+java-test-module-name-one
+Android.bp12345
+.
+java-test-module-name-six
+Android.bp12346
+.
+java-test-module-name-one
+Android.bp12345
+.
+java-test-module-name-six
+Aqwerty.bp12346
+.
+java-test-module-name-six
+Apoiuyt.bp12346
+.
+java-test-module-name-six
+Apoiuyt.bp12346
+.
+java-test-module-name-six
+Apoiuyt.bp12346
+.
+java-test-module-name-six
+Apoiuyt.bp12346
diff --git a/tools/metadata/testdata/file3.txt b/tools/metadata/testdata/file3.txt
new file mode 100644
index 0000000..81beed0
--- /dev/null
+++ b/tools/metadata/testdata/file3.txt
@@ -0,0 +1,13 @@
+
+.
+java-test-module-name-one
+Android.bp12345
+.
+java-test-module-name-two
+Android.bp12345
+.
+java-test-module-name-two
+Asdfghj.bp12345
+.
+java-test-module-name-two
+Azxcvbn.bp12345
diff --git a/tools/metadata/testdata/file4.txt b/tools/metadata/testdata/file4.txt
new file mode 100644
index 0000000..6a75900
--- /dev/null
+++ b/tools/metadata/testdata/file4.txt
@@ -0,0 +1,25 @@
+
+.
+java-test-module-name-one
+Android.bp12345
+.
+java-test-module-name-six
+Android.bp12346
+.
+java-test-module-name-one
+Android.bp12346
+.
+java-test-module-name-six
+Aqwerty.bp12346
+.
+java-test-module-name-six
+Apoiuyt.bp12346
+.
+java-test-module-name-six
+Apoiuyt.bp12346
+.
+java-test-module-name-six
+Apoiuyt.bp12346
+.
+java-test-module-name-six
+Apoiuyt.bp12346
diff --git a/tools/metadata/testdata/generatedOutputFile.txt b/tools/metadata/testdata/generatedOutputFile.txt
new file mode 100644
index 0000000..b0d382f
--- /dev/null
+++ b/tools/metadata/testdata/generatedOutputFile.txt
@@ -0,0 +1,22 @@
+
+.
+java-test-module-name-one
+Android.bp12345
+.
+java-test-module-name-six
+Android.bp12346
+.
+java-test-module-name-six
+Aqwerty.bp12346
+.
+java-test-module-name-six
+Apoiuyt.bp12346
+.
+java-test-module-name-two
+Android.bp12345
+.
+java-test-module-name-two
+Asdfghj.bp12345
+.
+java-test-module-name-two
+Azxcvbn.bp12345
\ No newline at end of file
diff --git a/tools/metadata/testdata/inputFiles.txt b/tools/metadata/testdata/inputFiles.txt
new file mode 100644
index 0000000..61e6a8d
--- /dev/null
+++ b/tools/metadata/testdata/inputFiles.txt
@@ -0,0 +1,2 @@
+file1.txt
+file2.txt
\ No newline at end of file
diff --git a/tools/metadata/testdata/inputFilesNegativeCase.txt b/tools/metadata/testdata/inputFilesNegativeCase.txt
new file mode 100644
index 0000000..17a9480
--- /dev/null
+++ b/tools/metadata/testdata/inputFilesNegativeCase.txt
@@ -0,0 +1,2 @@
+file3.txt
+file4.txt
\ No newline at end of file
diff --git a/tools/metadata/testdata/metadata_test.go b/tools/metadata/testdata/metadata_test.go
new file mode 100644
index 0000000..0cb80c3
--- /dev/null
+++ b/tools/metadata/testdata/metadata_test.go
@@ -0,0 +1,65 @@
+package main
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os/exec"
+ "strings"
+ "testing"
+)
+
+func TestMetadata(t *testing.T) {
+ cmd := exec.Command(
+ "metadata", "-inputFile", "./inputFiles.txt", "-outputFile",
+ "./generatedOutputFile.txt",
+ )
+ stderr, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("Error running metadata command: %s. Error: %v", stderr, err)
+ }
+
+ // Read the contents of the expected output file
+ expectedOutput, err := ioutil.ReadFile("./expectedOutputFile.txt")
+ if err != nil {
+ t.Fatalf("Error reading expected output file: %s", err)
+ }
+
+ // Read the contents of the generated output file
+ generatedOutput, err := ioutil.ReadFile("./generatedOutputFile.txt")
+ if err != nil {
+ t.Fatalf("Error reading generated output file: %s", err)
+ }
+
+ fmt.Println()
+
+ // Compare the contents
+ if string(expectedOutput) != string(generatedOutput) {
+ t.Errorf("Generated file contents do not match the expected output")
+ }
+}
+
+func TestMetadataNegativeCase(t *testing.T) {
+ cmd := exec.Command(
+ "metadata", "-inputFile", "./inputFilesNegativeCase.txt", "-outputFile",
+ "./generatedOutputFileNegativeCase.txt",
+ )
+ stderr, err := cmd.CombinedOutput()
+ if err == nil {
+ t.Fatalf(
+ "Expected an error, but the metadata command executed successfully. Output: %s",
+ stderr,
+ )
+ }
+
+ expectedError := "Conflicting trendy team IDs found for java-test-module" +
+ "-name-one at:\nAndroid.bp with teamId: 12346," +
+ "\nAndroid.bp with teamId: 12345"
+ if !strings.Contains(
+ strings.TrimSpace(string(stderr)), strings.TrimSpace(expectedError),
+ ) {
+ t.Errorf(
+ "Unexpected error message. Expected to contain: %s, Got: %s",
+ expectedError, stderr,
+ )
+ }
+}
diff --git a/tools/metadata/testdata/outputFile.txt b/tools/metadata/testdata/outputFile.txt
new file mode 100644
index 0000000..b0d382f
--- /dev/null
+++ b/tools/metadata/testdata/outputFile.txt
@@ -0,0 +1,22 @@
+
+.
+java-test-module-name-one
+Android.bp12345
+.
+java-test-module-name-six
+Android.bp12346
+.
+java-test-module-name-six
+Aqwerty.bp12346
+.
+java-test-module-name-six
+Apoiuyt.bp12346
+.
+java-test-module-name-two
+Android.bp12345
+.
+java-test-module-name-two
+Asdfghj.bp12345
+.
+java-test-module-name-two
+Azxcvbn.bp12345
\ No newline at end of file