/* * Copyright (C) 2017, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include "Collation.h" #include "frameworks/proto_logging/stats/stats_log_api_gen/test.pb.h" namespace android { namespace stats_log_api_gen { using std::map; using std::vector; /** * Return whether the map contains a vector of the elements provided. */ static bool map_contains_vector(const SignatureInfoMap& s, int count, ...) { va_list args; vector v(count); va_start(args, count); for (int i = 0; i < count; i++) { v[i] = static_cast(va_arg(args, int)); } va_end(args); return s.find(v) != s.end(); } /** * Expect that the provided map contains the elements provided. */ #define EXPECT_MAP_CONTAINS_SIGNATURE(s, ...) \ do { \ int count = sizeof((int[]){__VA_ARGS__}) / sizeof(int); \ EXPECT_TRUE(map_contains_vector(s, count, __VA_ARGS__)); \ } while (0) /** Expects that the provided atom has no enum values for any field. */ #define EXPECT_NO_ENUM_FIELD(atom) \ do { \ for (vector::const_iterator field = atom->fields.begin(); \ field != atom->fields.end(); field++) { \ EXPECT_TRUE(field->enumValues.empty()); \ } \ } while (0) /** Expects that exactly one specific field has expected enum values. */ #define EXPECT_HAS_ENUM_FIELD(atom, field_name, values) \ do { \ for (vector::const_iterator field = atom->fields.begin(); \ field != atom->fields.end(); field++) { \ if (field->name == field_name) { \ EXPECT_EQ(field->enumValues, values); \ } else { \ EXPECT_TRUE(field->enumValues.empty()); \ } \ } \ } while (0) /** * Test a correct collation, with all the types. */ TEST(CollationTest, CollateStats) { Atoms atoms; int errorCount = collate_atoms(Event::descriptor(), DEFAULT_MODULE_NAME, &atoms); EXPECT_EQ(0, errorCount); EXPECT_EQ(3ul, atoms.signatureInfoMap.size()); // IntAtom, AnotherIntAtom EXPECT_MAP_CONTAINS_SIGNATURE(atoms.signatureInfoMap, JAVA_TYPE_INT); // OutOfOrderAtom EXPECT_MAP_CONTAINS_SIGNATURE(atoms.signatureInfoMap, JAVA_TYPE_INT, JAVA_TYPE_INT); // AllTypesAtom EXPECT_MAP_CONTAINS_SIGNATURE(atoms.signatureInfoMap, JAVA_TYPE_ATTRIBUTION_CHAIN, // AttributionChain JAVA_TYPE_FLOAT, // float JAVA_TYPE_LONG, // int64 JAVA_TYPE_LONG, // uint64 JAVA_TYPE_INT, // int32 JAVA_TYPE_LONG, // fixed64 JAVA_TYPE_INT, // fixed32 JAVA_TYPE_BOOLEAN, // bool JAVA_TYPE_STRING, // string JAVA_TYPE_INT, // uint32 JAVA_TYPE_INT, // AnEnum JAVA_TYPE_INT, // sfixed32 JAVA_TYPE_LONG, // sfixed64 JAVA_TYPE_INT, // sint32 JAVA_TYPE_LONG // sint64 ); EXPECT_EQ(4ul, atoms.decls.size()); AtomDeclSet::const_iterator atomIt = atoms.decls.begin(); EXPECT_EQ(1, (*atomIt)->code); EXPECT_EQ("int_atom", (*atomIt)->name); EXPECT_EQ("IntAtom", (*atomIt)->message); EXPECT_NO_ENUM_FIELD((*atomIt)); atomIt++; EXPECT_EQ(2, (*atomIt)->code); EXPECT_EQ("out_of_order_atom", (*atomIt)->name); EXPECT_EQ("OutOfOrderAtom", (*atomIt)->message); EXPECT_NO_ENUM_FIELD((*atomIt)); atomIt++; EXPECT_EQ(3, (*atomIt)->code); EXPECT_EQ("another_int_atom", (*atomIt)->name); EXPECT_EQ("AnotherIntAtom", (*atomIt)->message); EXPECT_NO_ENUM_FIELD((*atomIt)); atomIt++; EXPECT_EQ(4, (*atomIt)->code); EXPECT_EQ("all_types_atom", (*atomIt)->name); EXPECT_EQ("AllTypesAtom", (*atomIt)->message); map enumValues; enumValues[0] = "VALUE0"; enumValues[1] = "VALUE1"; EXPECT_HAS_ENUM_FIELD((*atomIt), "enum_field", enumValues); atomIt++; EXPECT_EQ(atoms.decls.end(), atomIt); } /** * Test that event class that contains stuff other than the atoms is rejected. */ TEST(CollationTest, NonMessageTypeFails) { Atoms atoms; int errorCount = collate_atoms(IntAtom::descriptor(), DEFAULT_MODULE_NAME, &atoms); EXPECT_EQ(1, errorCount); } /** * Test that atoms that have non-primitive types or repeated fields are * rejected. */ TEST(CollationTest, FailOnBadTypes) { Atoms atoms; int errorCount = collate_atoms(BadTypesEvent::descriptor(), DEFAULT_MODULE_NAME, &atoms); EXPECT_EQ(4, errorCount); } /** * Test that atoms that skip field numbers (in the first position) are rejected. */ TEST(CollationTest, FailOnSkippedFieldsSingle) { Atoms atoms; int errorCount = collate_atoms(BadSkippedFieldSingle::descriptor(), DEFAULT_MODULE_NAME, &atoms); EXPECT_EQ(1, errorCount); } /** * Test that atoms that skip field numbers (not in the first position, and * multiple times) are rejected. */ TEST(CollationTest, FailOnSkippedFieldsMultiple) { Atoms atoms; int errorCount = collate_atoms(BadSkippedFieldMultiple::descriptor(), DEFAULT_MODULE_NAME, &atoms); EXPECT_EQ(2, errorCount); } /** * Test that atoms that have an attribution chain not in the first position are * rejected. */ TEST(CollationTest, FailBadAttributionNodePosition) { Atoms atoms; int errorCount = collate_atoms(BadAttributionNodePosition::descriptor(), DEFAULT_MODULE_NAME, &atoms); EXPECT_EQ(1, errorCount); } TEST(CollationTest, FailOnBadStateAtomOptions) { Atoms atoms; int errorCount = collate_atoms(BadStateAtoms::descriptor(), DEFAULT_MODULE_NAME, &atoms); EXPECT_EQ(3, errorCount); } TEST(CollationTest, PassOnGoodStateAtomOptions) { Atoms atoms; int errorCount = collate_atoms(GoodStateAtoms::descriptor(), DEFAULT_MODULE_NAME, &atoms); EXPECT_EQ(0, errorCount); } TEST(CollationTest, PassOnGoodBinaryFieldAtom) { Atoms atoms; int errorCount = collate_atoms(GoodEventWithBinaryFieldAtom::descriptor(), DEFAULT_MODULE_NAME, &atoms); EXPECT_EQ(0, errorCount); } TEST(CollationTest, FailOnBadBinaryFieldAtom) { Atoms atoms; int errorCount = collate_atoms(BadEventWithBinaryFieldAtom::descriptor(), DEFAULT_MODULE_NAME, &atoms); EXPECT_GT(errorCount, 0); } TEST(CollationTest, PassOnLogFromModuleAtom) { Atoms atoms; int errorCount = collate_atoms(ModuleAtoms::descriptor(), DEFAULT_MODULE_NAME, &atoms); EXPECT_EQ(errorCount, 0); EXPECT_EQ(atoms.decls.size(), 4ul); } TEST(CollationTest, RecognizeModuleAtom) { Atoms atoms; int errorCount = collate_atoms(ModuleAtoms::descriptor(), DEFAULT_MODULE_NAME, &atoms); EXPECT_EQ(errorCount, 0); EXPECT_EQ(atoms.decls.size(), 4ul); EXPECT_EQ(atoms.signatureInfoMap.size(), 2u); EXPECT_MAP_CONTAINS_SIGNATURE(atoms.signatureInfoMap, JAVA_TYPE_INT); EXPECT_MAP_CONTAINS_SIGNATURE(atoms.signatureInfoMap, JAVA_TYPE_STRING); SignatureInfoMap::const_iterator signatureInfoMapIt; const vector* signature; const FieldNumberToAtomDeclSet* fieldNumberToAtomDeclSet; FieldNumberToAtomDeclSet::const_iterator fieldNumberToAtomDeclSetIt; const AtomDeclSet* atomDeclSet; AtomDeclSet::const_iterator atomDeclSetIt; AtomDecl* atomDecl; FieldNumberToAnnotations* fieldNumberToAnnotations; FieldNumberToAnnotations::const_iterator fieldNumberToAnnotationsIt; const AnnotationSet* annotationSet; AnnotationSet::const_iterator annotationSetIt; Annotation* annotation; signatureInfoMapIt = atoms.signatureInfoMap.begin(); signature = &(signatureInfoMapIt->first); fieldNumberToAtomDeclSet = &signatureInfoMapIt->second; EXPECT_EQ(1ul, signature->size()); EXPECT_EQ(JAVA_TYPE_INT, signature->at(0)); EXPECT_EQ(1ul, fieldNumberToAtomDeclSet->size()); fieldNumberToAtomDeclSetIt = fieldNumberToAtomDeclSet->begin(); EXPECT_EQ(1, fieldNumberToAtomDeclSetIt->first); atomDeclSet = &fieldNumberToAtomDeclSetIt->second; EXPECT_EQ(2ul, atomDeclSet->size()); atomDeclSetIt = atomDeclSet->begin(); atomDecl = atomDeclSetIt->get(); EXPECT_EQ(1, atomDecl->code); fieldNumberToAnnotations = &atomDecl->fieldNumberToAnnotations; fieldNumberToAnnotationsIt = fieldNumberToAnnotations->find(1); EXPECT_NE(fieldNumberToAnnotations->end(), fieldNumberToAnnotationsIt); annotationSet = &fieldNumberToAnnotationsIt->second; EXPECT_EQ(1ul, annotationSet->size()); annotationSetIt = annotationSet->begin(); annotation = annotationSetIt->get(); EXPECT_EQ(ANNOTATION_ID_IS_UID, annotation->annotationId); EXPECT_EQ(1, annotation->atomId); EXPECT_EQ(ANNOTATION_TYPE_BOOL, annotation->type); EXPECT_TRUE(annotation->value.boolValue); atomDeclSetIt++; atomDecl = atomDeclSetIt->get(); EXPECT_EQ(3, atomDecl->code); fieldNumberToAnnotations = &atomDecl->fieldNumberToAnnotations; fieldNumberToAnnotationsIt = fieldNumberToAnnotations->find(1); EXPECT_NE(fieldNumberToAnnotations->end(), fieldNumberToAnnotationsIt); annotationSet = &fieldNumberToAnnotationsIt->second; EXPECT_EQ(1ul, annotationSet->size()); annotationSetIt = annotationSet->begin(); annotation = annotationSetIt->get(); EXPECT_EQ(ANNOTATION_ID_EXCLUSIVE_STATE, annotation->annotationId); EXPECT_EQ(3, annotation->atomId); EXPECT_EQ(ANNOTATION_TYPE_BOOL, annotation->type); EXPECT_TRUE(annotation->value.boolValue); signatureInfoMapIt++; signature = &signatureInfoMapIt->first; fieldNumberToAtomDeclSet = &signatureInfoMapIt->second; EXPECT_EQ(1ul, signature->size()); EXPECT_EQ(JAVA_TYPE_STRING, signature->at(0)); EXPECT_EQ(0ul, fieldNumberToAtomDeclSet->size()); } TEST(CollationTest, RecognizeModule1Atom) { Atoms atoms; const string moduleName = "module1"; int errorCount = collate_atoms(ModuleAtoms::descriptor(), moduleName, &atoms); EXPECT_EQ(errorCount, 0); EXPECT_EQ(atoms.decls.size(), 2ul); EXPECT_EQ(atoms.signatureInfoMap.size(), 1u); EXPECT_MAP_CONTAINS_SIGNATURE(atoms.signatureInfoMap, JAVA_TYPE_INT); SignatureInfoMap::const_iterator signatureInfoMapIt; const vector* signature; const FieldNumberToAtomDeclSet* fieldNumberToAtomDeclSet; FieldNumberToAtomDeclSet::const_iterator fieldNumberToAtomDeclSetIt; const AtomDeclSet* atomDeclSet; AtomDeclSet::const_iterator atomDeclSetIt; AtomDecl* atomDecl; FieldNumberToAnnotations* fieldNumberToAnnotations; FieldNumberToAnnotations::const_iterator fieldNumberToAnnotationsIt; const AnnotationSet* annotationSet; AnnotationSet::const_iterator annotationSetIt; Annotation* annotation; signatureInfoMapIt = atoms.signatureInfoMap.begin(); signature = &(signatureInfoMapIt->first); fieldNumberToAtomDeclSet = &signatureInfoMapIt->second; EXPECT_EQ(1ul, signature->size()); EXPECT_EQ(JAVA_TYPE_INT, signature->at(0)); EXPECT_EQ(1ul, fieldNumberToAtomDeclSet->size()); fieldNumberToAtomDeclSetIt = fieldNumberToAtomDeclSet->begin(); EXPECT_EQ(1, fieldNumberToAtomDeclSetIt->first); atomDeclSet = &fieldNumberToAtomDeclSetIt->second; EXPECT_EQ(2ul, atomDeclSet->size()); atomDeclSetIt = atomDeclSet->begin(); atomDecl = atomDeclSetIt->get(); EXPECT_EQ(1, atomDecl->code); fieldNumberToAnnotations = &atomDecl->fieldNumberToAnnotations; fieldNumberToAnnotationsIt = fieldNumberToAnnotations->find(1); EXPECT_NE(fieldNumberToAnnotations->end(), fieldNumberToAnnotationsIt); annotationSet = &fieldNumberToAnnotationsIt->second; EXPECT_EQ(1ul, annotationSet->size()); annotationSetIt = annotationSet->begin(); annotation = annotationSetIt->get(); EXPECT_EQ(ANNOTATION_ID_IS_UID, annotation->annotationId); EXPECT_EQ(1, annotation->atomId); EXPECT_EQ(ANNOTATION_TYPE_BOOL, annotation->type); EXPECT_TRUE(annotation->value.boolValue); atomDeclSetIt++; atomDecl = atomDeclSetIt->get(); EXPECT_EQ(3, atomDecl->code); fieldNumberToAnnotations = &atomDecl->fieldNumberToAnnotations; fieldNumberToAnnotationsIt = fieldNumberToAnnotations->find(1); EXPECT_NE(fieldNumberToAnnotations->end(), fieldNumberToAnnotationsIt); annotationSet = &fieldNumberToAnnotationsIt->second; EXPECT_EQ(1ul, annotationSet->size()); annotationSetIt = annotationSet->begin(); annotation = annotationSetIt->get(); EXPECT_EQ(ANNOTATION_ID_EXCLUSIVE_STATE, annotation->annotationId); EXPECT_EQ(3, annotation->atomId); EXPECT_EQ(ANNOTATION_TYPE_BOOL, annotation->type); EXPECT_TRUE(annotation->value.boolValue); } /** * Test that an atom is not a pushed nor pulled atom. */ TEST(CollationTest, InvalidAtomType) { Atoms atoms; int errorCount = collate_atoms(NotAPushNorPullAtom::descriptor(), DEFAULT_MODULE_NAME, &atoms); EXPECT_EQ(1, errorCount); } /** * Test that an atom was not declared in a `oneof` field. */ TEST(CollationTest, AtomNotDeclaredInAOneof) { Atoms atoms; int errorCount = collate_atoms(AtomNotInAOneof::descriptor(), DEFAULT_MODULE_NAME, &atoms); EXPECT_EQ(1, errorCount); } /** * Test a correct collation with pushed and pulled atoms. */ TEST(CollationTest, CollatePushedAndPulledAtoms) { Atoms atoms; int errorCount = collate_atoms(PushedAndPulledAtoms::descriptor(), DEFAULT_MODULE_NAME, &atoms); EXPECT_EQ(0, errorCount); EXPECT_EQ(1ul, atoms.signatureInfoMap.size()); EXPECT_EQ(2ul, atoms.pulledAtomsSignatureInfoMap.size()); // IntAtom EXPECT_MAP_CONTAINS_SIGNATURE(atoms.signatureInfoMap, JAVA_TYPE_INT); // AnotherIntAtom EXPECT_MAP_CONTAINS_SIGNATURE(atoms.pulledAtomsSignatureInfoMap, JAVA_TYPE_INT); // OutOfOrderAtom EXPECT_MAP_CONTAINS_SIGNATURE(atoms.pulledAtomsSignatureInfoMap, JAVA_TYPE_INT, JAVA_TYPE_INT); EXPECT_EQ(3ul, atoms.decls.size()); AtomDeclSet::const_iterator atomIt = atoms.decls.begin(); EXPECT_EQ(1, (*atomIt)->code); EXPECT_EQ("int_atom_1", (*atomIt)->name); EXPECT_EQ("IntAtom", (*atomIt)->message); EXPECT_NO_ENUM_FIELD((*atomIt)); atomIt++; EXPECT_EQ(10, (*atomIt)->code); EXPECT_EQ("another_int_atom", (*atomIt)->name); EXPECT_EQ("AnotherIntAtom", (*atomIt)->message); EXPECT_NO_ENUM_FIELD((*atomIt)); atomIt++; EXPECT_EQ(11, (*atomIt)->code); EXPECT_EQ("out_of_order_atom", (*atomIt)->name); EXPECT_EQ("OutOfOrderAtom", (*atomIt)->message); EXPECT_NO_ENUM_FIELD((*atomIt)); atomIt++; EXPECT_EQ(atoms.decls.end(), atomIt); } } // namespace stats_log_api_gen } // namespace android