Files
frameworks_base/tools/stats_log_api_gen/test_collation.cpp
Yao Chen bbdd67d19f Allow atoms to log fields in bytes format.
There are an increasing number of requests to log data in complex format to statsd, while the data
is not expected to be parsed or aggregated by statsd and only to be uploaded as events.

Instead of making an exception for each of these cases in a hard coded way, this CL add a feature to
annotate these field in atoms.proto and the stats-log-api-gen tool will produce byte array
interfaces for them.

Note that log_msg does not have byte array type, and only has string type, when statsd receives the
log, these fields are in string type. Only when the atom is written to proto, we will check if this
field should be bytes field and write it to protobuf in message format.

Change-Id: If53dd95c5826710c76d7fe982bf951a435dfc738
Fix: 118386797
Test: unit test & manual test
2018-10-24 13:12:13 -07:00

230 lines
6.6 KiB
C++

/*
* 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 <gtest/gtest.h>
#include "frameworks/base/tools/stats_log_api_gen/test.pb.h"
#include "Collation.h"
#include <stdio.h>
namespace android {
namespace stats_log_api_gen {
using std::map;
using std::set;
using std::vector;
/**
* Return whether the set contains a vector of the elements provided.
*/
static bool
set_contains_vector(const set<vector<java_type_t>>& s, int count, ...)
{
va_list args;
vector<java_type_t> v;
va_start(args, count);
for (int i=0; i<count; i++) {
v.push_back((java_type_t)va_arg(args, int));
}
va_end(args);
return s.find(v) != s.end();
}
/**
* Expect that the provided set contains the elements provided.
*/
#define EXPECT_SET_CONTAINS_SIGNATURE(s, ...) \
do { \
int count = sizeof((int[]){__VA_ARGS__})/sizeof(int); \
EXPECT_TRUE(set_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<AtomField>::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<AtomField>::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(), &atoms);
EXPECT_EQ(0, errorCount);
EXPECT_EQ(3ul, atoms.signatures.size());
// IntAtom, AnotherIntAtom
EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures, JAVA_TYPE_INT);
// OutOfOrderAtom
EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures, JAVA_TYPE_INT, JAVA_TYPE_INT);
// AllTypesAtom
EXPECT_SET_CONTAINS_SIGNATURE(
atoms.signatures,
JAVA_TYPE_ATTRIBUTION_CHAIN, // AttributionChain
JAVA_TYPE_DOUBLE, // double
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
);
set<AtomDecl>::const_iterator atom = atoms.decls.begin();
EXPECT_EQ(1, atom->code);
EXPECT_EQ("int_atom", atom->name);
EXPECT_EQ("IntAtom", atom->message);
EXPECT_NO_ENUM_FIELD(atom);
atom++;
EXPECT_EQ(2, atom->code);
EXPECT_EQ("out_of_order_atom", atom->name);
EXPECT_EQ("OutOfOrderAtom", atom->message);
EXPECT_NO_ENUM_FIELD(atom);
atom++;
EXPECT_EQ(3, atom->code);
EXPECT_EQ("another_int_atom", atom->name);
EXPECT_EQ("AnotherIntAtom", atom->message);
EXPECT_NO_ENUM_FIELD(atom);
atom++;
EXPECT_EQ(4, atom->code);
EXPECT_EQ("all_types_atom", atom->name);
EXPECT_EQ("AllTypesAtom", atom->message);
map<int, string> enumValues;
enumValues[0] = "VALUE0";
enumValues[1] = "VALUE1";
EXPECT_HAS_ENUM_FIELD(atom, "enum_field", enumValues);
atom++;
EXPECT_TRUE(atom == atoms.decls.end());
}
/**
* Test that event class that contains stuff other than the atoms is rejected.
*/
TEST(CollationTest, NonMessageTypeFails) {
Atoms atoms;
int errorCount = collate_atoms(IntAtom::descriptor(), &atoms);
EXPECT_EQ(1, errorCount);
}
/**
* Test that atoms that have non-primitive types are rejected.
*/
TEST(CollationTest, FailOnBadTypes) {
Atoms atoms;
int errorCount = collate_atoms(BadTypesEvent::descriptor(), &atoms);
EXPECT_EQ(2, 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(), &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(), &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(), &atoms);
EXPECT_EQ(1, errorCount);
}
TEST(CollationTest, FailOnBadStateAtomOptions) {
Atoms atoms;
int errorCount = collate_atoms(BadStateAtoms::descriptor(), &atoms);
EXPECT_EQ(3, errorCount);
}
TEST(CollationTest, PassOnGoodStateAtomOptions) {
Atoms atoms;
int errorCount = collate_atoms(GoodStateAtoms::descriptor(), &atoms);
EXPECT_EQ(0, errorCount);
}
TEST(CollationTest, PassOnGoodBinaryFieldAtom) {
Atoms atoms;
int errorCount =
collate_atoms(GoodEventWithBinaryFieldAtom::descriptor(), &atoms);
EXPECT_EQ(0, errorCount);
}
TEST(CollationTest, FailOnBadBinaryFieldAtom) {
Atoms atoms;
int errorCount =
collate_atoms(BadEventWithBinaryFieldAtom::descriptor(), &atoms);
EXPECT_TRUE(errorCount > 0);
}
} // namespace stats_log_api_gen
} // namespace android