summaryrefslogtreecommitdiff
path: root/cmds/statsd/tests/external/StatsCallbackPuller_test.cpp
diff options
context:
space:
mode:
authorXin Li <delphij@google.com>2020-09-10 17:22:01 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2020-09-10 17:22:01 +0000
commit8ac6741e47c76bde065f868ea64d2f04541487b9 (patch)
tree1a679458fdbd8d370692d56791e2bf83acee35b5 /cmds/statsd/tests/external/StatsCallbackPuller_test.cpp
parent3de940cc40b1e3fdf8224e18a8308a16768cbfa8 (diff)
parentc64112eb974e9aa7638aead998f07a868acfb5a7 (diff)
Merge "Merge Android R"
Diffstat (limited to 'cmds/statsd/tests/external/StatsCallbackPuller_test.cpp')
-rw-r--r--cmds/statsd/tests/external/StatsCallbackPuller_test.cpp219
1 files changed, 219 insertions, 0 deletions
diff --git a/cmds/statsd/tests/external/StatsCallbackPuller_test.cpp b/cmds/statsd/tests/external/StatsCallbackPuller_test.cpp
new file mode 100644
index 000000000000..85a60886349e
--- /dev/null
+++ b/cmds/statsd/tests/external/StatsCallbackPuller_test.cpp
@@ -0,0 +1,219 @@
+// Copyright (C) 2019 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 "src/external/StatsCallbackPuller.h"
+
+#include <aidl/android/os/BnPullAtomCallback.h>
+#include <aidl/android/os/IPullAtomResultReceiver.h>
+#include <aidl/android/util/StatsEventParcel.h>
+#include <android/binder_interface_utils.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <stdio.h>
+
+#include <chrono>
+#include <thread>
+#include <vector>
+
+#include "../metrics/metrics_test_helper.h"
+#include "src/stats_log_util.h"
+#include "stats_event.h"
+#include "tests/statsd_test_util.h"
+
+#ifdef __ANDROID__
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using namespace testing;
+using Status = ::ndk::ScopedAStatus;
+using aidl::android::os::BnPullAtomCallback;
+using aidl::android::os::IPullAtomResultReceiver;
+using aidl::android::util::StatsEventParcel;
+using ::ndk::SharedRefBase;
+using std::make_shared;
+using std::shared_ptr;
+using std::vector;
+using std::this_thread::sleep_for;
+using testing::Contains;
+
+namespace {
+int pullTagId = -12;
+bool pullSuccess;
+vector<int64_t> values;
+int64_t pullDelayNs;
+int64_t pullTimeoutNs;
+int64_t pullCoolDownNs;
+std::thread pullThread;
+
+AStatsEvent* createSimpleEvent(int64_t value) {
+ AStatsEvent* event = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(event, pullTagId);
+ AStatsEvent_writeInt64(event, value);
+ AStatsEvent_build(event);
+ return event;
+}
+
+void executePull(const shared_ptr<IPullAtomResultReceiver>& resultReceiver) {
+ // Convert stats_events into StatsEventParcels.
+ vector<StatsEventParcel> parcels;
+ for (int i = 0; i < values.size(); i++) {
+ AStatsEvent* event = createSimpleEvent(values[i]);
+ size_t size;
+ uint8_t* buffer = AStatsEvent_getBuffer(event, &size);
+
+ StatsEventParcel p;
+ // vector.assign() creates a copy, but this is inevitable unless
+ // stats_event.h/c uses a vector as opposed to a buffer.
+ p.buffer.assign(buffer, buffer + size);
+ parcels.push_back(std::move(p));
+ AStatsEvent_release(event);
+ }
+
+ sleep_for(std::chrono::nanoseconds(pullDelayNs));
+ resultReceiver->pullFinished(pullTagId, pullSuccess, parcels);
+}
+
+class FakePullAtomCallback : public BnPullAtomCallback {
+public:
+ Status onPullAtom(int atomTag,
+ const shared_ptr<IPullAtomResultReceiver>& resultReceiver) override {
+ // Force pull to happen in separate thread to simulate binder.
+ pullThread = std::thread(executePull, resultReceiver);
+ return Status::ok();
+ }
+};
+
+class StatsCallbackPullerTest : public ::testing::Test {
+public:
+ StatsCallbackPullerTest() {
+ }
+
+ void SetUp() override {
+ pullSuccess = false;
+ pullDelayNs = 0;
+ values.clear();
+ pullTimeoutNs = 10000000000LL; // 10 seconds.
+ pullCoolDownNs = 1000000000; // 1 second.
+ }
+
+ void TearDown() override {
+ if (pullThread.joinable()) {
+ pullThread.join();
+ }
+ values.clear();
+ }
+};
+} // Anonymous namespace.
+
+TEST_F(StatsCallbackPullerTest, PullSuccess) {
+ shared_ptr<FakePullAtomCallback> cb = SharedRefBase::make<FakePullAtomCallback>();
+ int64_t value = 43;
+ pullSuccess = true;
+ values.push_back(value);
+
+ StatsCallbackPuller puller(pullTagId, cb, pullCoolDownNs, pullTimeoutNs, {});
+
+ vector<std::shared_ptr<LogEvent>> dataHolder;
+ int64_t startTimeNs = getElapsedRealtimeNs();
+ EXPECT_TRUE(puller.PullInternal(&dataHolder));
+ int64_t endTimeNs = getElapsedRealtimeNs();
+
+ ASSERT_EQ(1, dataHolder.size());
+ EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
+ EXPECT_LT(startTimeNs, dataHolder[0]->GetElapsedTimestampNs());
+ EXPECT_GT(endTimeNs, dataHolder[0]->GetElapsedTimestampNs());
+ ASSERT_EQ(1, dataHolder[0]->size());
+ EXPECT_EQ(value, dataHolder[0]->getValues()[0].mValue.int_value);
+}
+
+TEST_F(StatsCallbackPullerTest, PullFail) {
+ shared_ptr<FakePullAtomCallback> cb = SharedRefBase::make<FakePullAtomCallback>();
+ pullSuccess = false;
+ int64_t value = 1234;
+ values.push_back(value);
+
+ StatsCallbackPuller puller(pullTagId, cb, pullCoolDownNs, pullTimeoutNs, {});
+
+ vector<shared_ptr<LogEvent>> dataHolder;
+ EXPECT_FALSE(puller.PullInternal(&dataHolder));
+ ASSERT_EQ(0, dataHolder.size());
+}
+
+TEST_F(StatsCallbackPullerTest, PullTimeout) {
+ shared_ptr<FakePullAtomCallback> cb = SharedRefBase::make<FakePullAtomCallback>();
+ pullSuccess = true;
+ pullDelayNs = MillisToNano(5); // 5ms.
+ pullTimeoutNs = 10000; // 10 microseconds.
+ int64_t value = 4321;
+ values.push_back(value);
+
+ StatsCallbackPuller puller(pullTagId, cb, pullCoolDownNs, pullTimeoutNs, {});
+
+ vector<shared_ptr<LogEvent>> dataHolder;
+ int64_t startTimeNs = getElapsedRealtimeNs();
+ // Returns true to let StatsPuller code evaluate the timeout.
+ EXPECT_TRUE(puller.PullInternal(&dataHolder));
+ int64_t endTimeNs = getElapsedRealtimeNs();
+ int64_t actualPullDurationNs = endTimeNs - startTimeNs;
+
+ // Pull should take at least the timeout amount of time, but should stop early because the delay
+ // is bigger.
+ EXPECT_LT(pullTimeoutNs, actualPullDurationNs);
+ EXPECT_GT(pullDelayNs, actualPullDurationNs);
+ ASSERT_EQ(0, dataHolder.size());
+
+ // Let the pull return and make sure that the dataHolder is not modified.
+ pullThread.join();
+ ASSERT_EQ(0, dataHolder.size());
+}
+
+// Register a puller and ensure that the timeout logic works.
+TEST_F(StatsCallbackPullerTest, RegisterAndTimeout) {
+ shared_ptr<FakePullAtomCallback> cb = SharedRefBase::make<FakePullAtomCallback>();
+ pullSuccess = true;
+ pullDelayNs = MillisToNano(5); // 5 ms.
+ pullTimeoutNs = 10000; // 10 microsseconds.
+ int64_t value = 4321;
+ int32_t uid = 123;
+ values.push_back(value);
+
+ sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+ pullerManager->RegisterPullAtomCallback(uid, pullTagId, pullCoolDownNs, pullTimeoutNs,
+ vector<int32_t>(), cb);
+ vector<shared_ptr<LogEvent>> dataHolder;
+ int64_t startTimeNs = getElapsedRealtimeNs();
+ // Returns false, since StatsPuller code will evaluate the timeout.
+ EXPECT_FALSE(pullerManager->Pull(pullTagId, {uid}, startTimeNs, &dataHolder));
+ int64_t endTimeNs = getElapsedRealtimeNs();
+ int64_t actualPullDurationNs = endTimeNs - startTimeNs;
+
+ // Pull should take at least the timeout amount of time, but should stop early because the delay
+ // is bigger. Make sure that the time is closer to the timeout, than to the intended delay.
+ EXPECT_LT(pullTimeoutNs, actualPullDurationNs);
+ EXPECT_GT(pullDelayNs / 5, actualPullDurationNs);
+ ASSERT_EQ(0, dataHolder.size());
+
+ // Let the pull return and make sure that the dataHolder is not modified.
+ pullThread.join();
+ ASSERT_EQ(0, dataHolder.size());
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif