#include "src/metrics/RestrictedEventMetricProducer.h" #include #include "flags/FlagProvider.h" #include "metrics_test_helper.h" #include "stats_annotations.h" #include "tests/statsd_test_util.h" #include "utils/DbUtils.h" using namespace testing; using std::string; using std::stringstream; using std::vector; #ifdef __ANDROID__ namespace android { namespace os { namespace statsd { namespace { const ConfigKey configKey(/*uid=*/0, /*id=*/12345); const int64_t metricId1 = 123; const int64_t metricId2 = 456; bool metricTableExist(int64_t metricId) { stringstream query; query << "SELECT * FROM metric_" << metricId; vector columnTypes; vector> rows; vector columnNames; string err; return dbutils::query(configKey, query.str(), rows, columnTypes, columnNames, err); } } // anonymous namespace class RestrictedEventMetricProducerTest : public Test { protected: void SetUp() override { if (!isAtLeastU()) { GTEST_SKIP(); } } void TearDown() override { if (!isAtLeastU()) { GTEST_SKIP(); } dbutils::deleteDb(configKey); FlagProvider::getInstance().resetOverrides(); } }; TEST_F(RestrictedEventMetricProducerTest, TestOnMatchedLogEventMultipleEvents) { EventMetric metric; metric.set_id(metricId1); sp provider = makeMockConfigMetadataProvider(/*enabled=*/false); RestrictedEventMetricProducer producer(configKey, metric, /*conditionIndex=*/-1, /*initialConditionCache=*/{}, new ConditionWizard(), /*protoHash=*/0x1234567890, /*startTimeNs=*/0, provider); std::unique_ptr event1 = CreateRestrictedLogEvent(/*atomTag=*/123, /*timestampNs=*/1); std::unique_ptr event2 = CreateRestrictedLogEvent(/*atomTag=*/123, /*timestampNs=*/3); producer.onMatchedLogEvent(/*matcherIndex=*/1, *event1); producer.onMatchedLogEvent(/*matcherIndex=*/1, *event2); producer.flushRestrictedData(); stringstream query; query << "SELECT * FROM metric_" << metricId1; string err; vector columnTypes; std::vector columnNames; vector> rows; dbutils::query(configKey, query.str(), rows, columnTypes, columnNames, err); ASSERT_EQ(rows.size(), 2); EXPECT_EQ(columnTypes.size(), 3 + event1->getValues().size()); // col 0:2 are reserved for metadata. EXPECT_EQ(/*tagId=*/rows[0][0], to_string(event1->GetTagId())); EXPECT_EQ(/*elapsedTimestampNs=*/rows[0][1], to_string(event1->GetElapsedTimestampNs())); EXPECT_EQ(/*elapsedTimestampNs=*/rows[1][1], to_string(event2->GetElapsedTimestampNs())); EXPECT_THAT(columnNames, ElementsAre("atomId", "elapsedTimestampNs", "wallTimestampNs", "field_1")); } TEST_F(RestrictedEventMetricProducerTest, TestOnMatchedLogEventMultipleFields) { EventMetric metric; metric.set_id(metricId2); sp provider = makeMockConfigMetadataProvider(/*enabled=*/false); RestrictedEventMetricProducer producer(configKey, metric, /*conditionIndex=*/-1, /*initialConditionCache=*/{}, new ConditionWizard(), /*protoHash=*/0x1234567890, /*startTimeNs=*/0, provider); AStatsEvent* statsEvent = AStatsEvent_obtain(); AStatsEvent_setAtomId(statsEvent, 1); AStatsEvent_addInt32Annotation(statsEvent, ASTATSLOG_ANNOTATION_ID_RESTRICTION_CATEGORY, ASTATSLOG_RESTRICTION_CATEGORY_DIAGNOSTIC); AStatsEvent_overwriteTimestamp(statsEvent, 1); AStatsEvent_writeString(statsEvent, "111"); AStatsEvent_writeInt32(statsEvent, 11); AStatsEvent_writeFloat(statsEvent, 11.0); LogEvent logEvent(/*uid=*/0, /*pid=*/0); parseStatsEventToLogEvent(statsEvent, &logEvent); producer.onMatchedLogEvent(/*matcherIndex=1*/ 1, logEvent); producer.flushRestrictedData(); stringstream query; query << "SELECT * FROM metric_" << metricId2; string err; vector columnTypes; std::vector columnNames; vector> rows; EXPECT_TRUE(dbutils::query(configKey, query.str(), rows, columnTypes, columnNames, err)); ASSERT_EQ(rows.size(), 1); EXPECT_EQ(columnTypes.size(), 3 + logEvent.getValues().size()); // col 0:2 are reserved for metadata. EXPECT_EQ(/*field1=*/rows[0][3], "111"); EXPECT_EQ(/*field2=*/rows[0][4], "11"); EXPECT_FLOAT_EQ(/*field3=*/std::stof(rows[0][5]), 11.0); EXPECT_THAT(columnNames, ElementsAre("atomId", "elapsedTimestampNs", "wallTimestampNs", "field_1", "field_2", "field_3")); } TEST_F(RestrictedEventMetricProducerTest, TestOnMatchedLogEventWithCondition) { EventMetric metric; metric.set_id(metricId1); metric.set_condition(StringToId("SCREEN_ON")); sp provider = makeMockConfigMetadataProvider(/*enabled=*/false); RestrictedEventMetricProducer producer(configKey, metric, /*conditionIndex=*/0, /*initialConditionCache=*/{ConditionState::kUnknown}, new ConditionWizard(), /*protoHash=*/0x1234567890, /*startTimeNs=*/0, provider); std::unique_ptr event1 = CreateRestrictedLogEvent(/*atomTag=*/123, /*timestampNs=*/1); std::unique_ptr event2 = CreateRestrictedLogEvent(/*atomTag=*/123, /*timestampNs=*/3); producer.onConditionChanged(true, 0); producer.onMatchedLogEvent(/*matcherIndex=*/1, *event1); producer.onConditionChanged(false, 1); producer.onMatchedLogEvent(/*matcherIndex=*/1, *event2); producer.flushRestrictedData(); std::stringstream query; query << "SELECT * FROM metric_" << metricId1; string err; std::vector columnTypes; std::vector columnNames; std::vector> rows; dbutils::query(configKey, query.str(), rows, columnTypes, columnNames, err); ASSERT_EQ(rows.size(), 1); EXPECT_EQ(columnTypes.size(), 3 + event1->getValues().size()); EXPECT_EQ(/*elapsedTimestampNs=*/rows[0][1], to_string(event1->GetElapsedTimestampNs())); EXPECT_THAT(columnNames, ElementsAre("atomId", "elapsedTimestampNs", "wallTimestampNs", "field_1")); } TEST_F(RestrictedEventMetricProducerTest, TestOnDumpReportNoOp) { EventMetric metric; metric.set_id(metricId1); sp provider = makeMockConfigMetadataProvider(/*enabled=*/false); RestrictedEventMetricProducer producer(configKey, metric, /*conditionIndex=*/-1, /*initialConditionCache=*/{}, new ConditionWizard(), /*protoHash=*/0x1234567890, /*startTimeNs=*/0, provider); std::unique_ptr event1 = CreateRestrictedLogEvent(/*timestampNs=*/1); producer.onMatchedLogEvent(/*matcherIndex=*/1, *event1); ProtoOutputStream output; std::set strSet; producer.onDumpReport(/*dumpTimeNs=*/10, /*include_current_partial_bucket=*/true, /*erase_data=*/true, FAST, &strSet, &output); ASSERT_EQ(output.size(), 0); ASSERT_EQ(strSet.size(), 0); } TEST_F(RestrictedEventMetricProducerTest, TestOnMetricRemove) { EventMetric metric; metric.set_id(metricId1); sp provider = makeMockConfigMetadataProvider(/*enabled=*/false); RestrictedEventMetricProducer producer(configKey, metric, /*conditionIndex=*/-1, /*initialConditionCache=*/{}, new ConditionWizard(), /*protoHash=*/0x1234567890, /*startTimeNs=*/0, provider); EXPECT_FALSE(metricTableExist(metricId1)); std::unique_ptr event1 = CreateRestrictedLogEvent(/*timestampNs=*/1); producer.onMatchedLogEvent(/*matcherIndex=*/1, *event1); producer.flushRestrictedData(); EXPECT_TRUE(metricTableExist(metricId1)); producer.onMetricRemove(); EXPECT_FALSE(metricTableExist(metricId1)); } TEST_F(RestrictedEventMetricProducerTest, TestRestrictedEventMetricTtlDeletesFirstEvent) { EventMetric metric; metric.set_id(metricId1); sp provider = makeMockConfigMetadataProvider(/*enabled=*/false); RestrictedEventMetricProducer producer(configKey, metric, /*conditionIndex=*/-1, /*initialConditionCache=*/{}, new ConditionWizard(), /*protoHash=*/0x1234567890, /*startTimeNs=*/0, provider); int64_t currentTimeNs = getWallClockNs(); int64_t eightDaysAgo = currentTimeNs - 8 * 24 * 3600 * NS_PER_SEC; std::unique_ptr event1 = CreateRestrictedLogEvent(/*atomTag=*/123, /*timestampNs=*/1); event1->setLogdWallClockTimestampNs(eightDaysAgo); std::unique_ptr event2 = CreateRestrictedLogEvent(/*atomTag=*/123, /*timestampNs=*/3); event2->setLogdWallClockTimestampNs(currentTimeNs); producer.onMatchedLogEvent(/*matcherIndex=*/1, *event1); producer.onMatchedLogEvent(/*matcherIndex=*/1, *event2); producer.flushRestrictedData(); sqlite3* dbHandle = dbutils::getDb(configKey); producer.enforceRestrictedDataTtl(dbHandle, currentTimeNs + 100); dbutils::closeDb(dbHandle); std::stringstream query; query << "SELECT * FROM metric_" << metricId1; string err; std::vector columnTypes; std::vector columnNames; std::vector> rows; dbutils::query(configKey, query.str(), rows, columnTypes, columnNames, err); ASSERT_EQ(rows.size(), 1); EXPECT_EQ(columnTypes.size(), 3 + event1->getValues().size()); EXPECT_THAT(columnNames, ElementsAre("atomId", "elapsedTimestampNs", "wallTimestampNs", "field_1")); EXPECT_THAT(rows[0], ElementsAre(to_string(event2->GetTagId()), to_string(event2->GetElapsedTimestampNs()), to_string(currentTimeNs), _)); } TEST_F(RestrictedEventMetricProducerTest, TestLoadMetricMetadataSetsCategory) { metadata::MetricMetadata metricMetadata; metricMetadata.set_metric_id(metricId1); metricMetadata.set_restricted_category(1); // CATEGORY_DIAGNOSTIC EventMetric metric; metric.set_id(metricId1); sp provider = makeMockConfigMetadataProvider(/*enabled=*/false); RestrictedEventMetricProducer producer(configKey, metric, /*conditionIndex=*/-1, /*initialConditionCache=*/{}, new ConditionWizard(), /*protoHash=*/0x1234567890, /*startTimeNs=*/0, provider); producer.loadMetricMetadataFromProto(metricMetadata); EXPECT_EQ(producer.getRestrictionCategory(), CATEGORY_DIAGNOSTIC); } } // namespace statsd } // namespace os } // namespace android #else GTEST_LOG_(INFO) << "This test does nothing.\n"; #endif