1 /*
2 * Copyright (C) 2024 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <android-base/file.h>
18 #include <android-base/stringprintf.h>
19 #include <gtest/gtest.h>
20
21 #include <algorithm>
22 #include <thread>
23
24 #include "perfmgr/EventNode.h"
25
26 namespace android {
27 namespace perfmgr {
28
29 using std::literals::chrono_literals::operator""ms;
30
31 constexpr double kTIMING_TOLERANCE_MS = std::chrono::milliseconds(25).count();
32 constexpr auto kSLEEP_TOLERANCE_MS = 2ms;
33
34 // Test init with no default value
TEST(EventNodeTest,NoInitDefaultTest)35 TEST(EventNodeTest, NoInitDefaultTest) {
36 std::string node_val = "uninitialize";
37 auto update_callback = [&node_val](const std::string &, const std::string &,
38 const std::string &val) { node_val = val; };
39 EventNode t("EventName", "<Event>:Node", {{"value0"}, {"value1"}, {"value2"}}, 1, false,
40 update_callback);
41 t.Update(false);
42 EXPECT_EQ(node_val, "uninitialize");
43 }
44
45 // Test init with default value
TEST(EventNodeTest,InitDefaultTest)46 TEST(EventNodeTest, InitDefaultTest) {
47 std::string node_val = "uninitialize";
48 auto update_callback = [&node_val](const std::string &, const std::string &,
49 const std::string &val) { node_val = val; };
50 EventNode t("EventName", "<Event>:Node", {{"value0"}, {"value1"}, {"value2"}}, 1, true,
51 update_callback);
52 t.Update(false);
53 EXPECT_EQ(node_val, "value1");
54 EventNode t2("EventName", "<Event>:Node", {{"value0"}, {"value1"}, {"value2"}}, 0, true,
55 update_callback);
56 t2.Update(false);
57 EXPECT_EQ(node_val, "value0");
58 }
59
60 // Test DumpToFd
TEST(EventNodeTest,DumpToFdTest)61 TEST(EventNodeTest, DumpToFdTest) {
62 std::string node_val = "uninitialize";
63 auto update_callback = [&node_val](const std::string &, const std::string &,
64 const std::string &val) { node_val = val; };
65 EventNode t("EventName", "<Event>:Node", {{"value0"}, {"value1"}, {"value2"}}, 1, true,
66 update_callback);
67 t.Update(false);
68 t.Update(false);
69 TemporaryFile dumptf;
70 t.DumpToFd(dumptf.fd);
71 fsync(dumptf.fd);
72 std::string buf(android::base::StringPrintf(
73 "Node Name\t"
74 "Event Path\t"
75 "Current Index\t"
76 "Current Value\n"
77 "%s\t%s\t%zu\t%s\n",
78 "EventName", "<Event>:Node", static_cast<size_t>(1), "value1"));
79 std::string s;
80 EXPECT_TRUE(android::base::ReadFileToString(dumptf.path, &s)) << strerror(errno);
81 EXPECT_EQ(buf, s);
82 }
83
84 // Test GetValueIndex
TEST(EventNodeTest,GetValueIndexTest)85 TEST(EventNodeTest, GetValueIndexTest) {
86 std::string node_val = "uninitialize";
87 auto update_callback = [&node_val](const std::string &, const std::string &,
88 const std::string &val) { node_val = val; };
89 EventNode t("EventName", "<Event>:Node", {{"value0"}, {"value1"}, {"value2"}}, 1, false,
90 update_callback);
91 std::size_t index = 0;
92 EXPECT_TRUE(t.GetValueIndex("value2", &index));
93 EXPECT_EQ(2u, index);
94 index = 1234;
95 EXPECT_FALSE(t.GetValueIndex("NON_EXIST", &index));
96 EXPECT_EQ(1234u, index);
97 }
98
99 // Test GetValues
TEST(EventNodeTest,GetValuesTest)100 TEST(EventNodeTest, GetValuesTest) {
101 std::string node_val = "uninitialize";
102 auto update_callback = [&node_val](const std::string &, const std::string &,
103 const std::string &val) { node_val = val; };
104 EventNode t("EventName", "<Event>:Node", {{"value0"}, {"value1"}, {"value2"}}, 1, false,
105 update_callback);
106 std::vector values = t.GetValues();
107 EXPECT_EQ(3u, values.size());
108 EXPECT_EQ("value0", values[0]);
109 EXPECT_EQ("value1", values[1]);
110 EXPECT_EQ("value2", values[2]);
111 }
112
113 // Test get more properties
TEST(EventNodeTest,GetPropertiesTest)114 TEST(EventNodeTest, GetPropertiesTest) {
115 std::string node_val = "uninitialize";
116 auto update_callback = [&node_val](const std::string &, const std::string &,
117 const std::string &val) { node_val = val; };
118 std::string test_name = "TESTREQ_1";
119 std::string test_path = "TEST_PATH";
120 EventNode t(test_name, test_path, {}, 0, false, update_callback);
121 EXPECT_EQ(test_name, t.GetName());
122 EXPECT_EQ(test_path, t.GetPath());
123 EXPECT_EQ(0u, t.GetValues().size());
124 EXPECT_EQ(0u, t.GetDefaultIndex());
125 EXPECT_FALSE(t.GetResetOnInit());
126 }
127
128 // Test add request
TEST(EventNodeTest,AddRequestTest)129 TEST(EventNodeTest, AddRequestTest) {
130 std::string node_val = "uninitialize";
131 auto update_callback = [&node_val](const std::string &, const std::string &,
132 const std::string &val) { node_val = val; };
133 EventNode t("EventName", "<Event>:Node", {{"value0"}, {"value1"}, {""}}, 2, true,
134 update_callback);
135 auto start = std::chrono::steady_clock::now();
136 EXPECT_TRUE(t.AddRequest(1, "INTERACTION", start + 500ms));
137 std::chrono::milliseconds expire_time = t.Update(true);
138 // Add request @ value1
139 EXPECT_EQ(node_val, "value1");
140 EXPECT_NEAR(std::chrono::milliseconds(500).count(), expire_time.count(), kTIMING_TOLERANCE_MS);
141 // Add request @ value0 higher prio than value1
142 EXPECT_TRUE(t.AddRequest(0, "LAUNCH", start + 200ms));
143 expire_time = t.Update(true);
144 EXPECT_EQ(node_val, "value0");
145 EXPECT_NEAR(std::chrono::milliseconds(200).count(), expire_time.count(), kTIMING_TOLERANCE_MS);
146 // Let high prio request timeout, now only request @ value1 active
147 std::this_thread::sleep_for(expire_time + kSLEEP_TOLERANCE_MS);
148 expire_time = t.Update(true);
149 EXPECT_EQ(node_val, "value1");
150 EXPECT_NEAR(std::chrono::milliseconds(300).count(), expire_time.count(), kTIMING_TOLERANCE_MS);
151 // Let all requests timeout, now default value2
152 std::this_thread::sleep_for(expire_time + kSLEEP_TOLERANCE_MS);
153 expire_time = t.Update(true);
154 EXPECT_EQ(node_val, "");
155 EXPECT_EQ(std::chrono::milliseconds::max(), expire_time);
156 }
157
158 // Test remove request
TEST(EventNodeTest,RemoveRequestTest)159 TEST(EventNodeTest, RemoveRequestTest) {
160 std::string node_val = "uninitialize";
161 auto update_callback = [&node_val](const std::string &, const std::string &,
162 const std::string &val) { node_val = val; };
163 EventNode t("EventName", "<Event>:Node", {{"value0"}, {"value1"}, {"value2"}}, 2, true,
164 update_callback);
165 auto start = std::chrono::steady_clock::now();
166 EXPECT_TRUE(t.AddRequest(1, "INTERACTION", start + 500ms));
167 std::chrono::milliseconds expire_time = t.Update(true);
168 // Add request @ value1
169 EXPECT_EQ(node_val, "value1");
170 EXPECT_NEAR(std::chrono::milliseconds(500).count(), expire_time.count(), kTIMING_TOLERANCE_MS);
171 // Add request @ value0 higher prio than value1
172 EXPECT_TRUE(t.AddRequest(0, "LAUNCH", start + 200ms));
173 expire_time = t.Update(true);
174 EXPECT_EQ(node_val, "value0");
175 EXPECT_NEAR(std::chrono::milliseconds(200).count(), expire_time.count(), kTIMING_TOLERANCE_MS);
176 // Remove high prio request, now only request @ value1 active
177 t.RemoveRequest("LAUNCH");
178 expire_time = t.Update(true);
179 EXPECT_EQ(node_val, "value1");
180 EXPECT_NEAR(std::chrono::milliseconds(500).count(), expire_time.count(), kTIMING_TOLERANCE_MS);
181 // Remove request, now default value2
182 t.RemoveRequest("INTERACTION");
183 expire_time = t.Update(true);
184 EXPECT_EQ(node_val, "value2");
185 EXPECT_EQ(std::chrono::milliseconds::max(), expire_time);
186 }
187
188 // Test add request
TEST(EventNodeTest,AddRequestTestOverride)189 TEST(EventNodeTest, AddRequestTestOverride) {
190 std::string node_val = "uninitialize";
191 auto update_callback = [&node_val](const std::string &, const std::string &,
192 const std::string &val) { node_val = val; };
193 EventNode t("EventName", "<Event>:Node", {{"value0"}, {"value1"}, {"value2"}}, 2, true,
194 update_callback);
195 auto start = std::chrono::steady_clock::now();
196 EXPECT_TRUE(t.AddRequest(1, "INTERACTION", start + 500ms));
197 std::chrono::milliseconds expire_time = t.Update(true);
198 // Add request @ value1
199 EXPECT_EQ(node_val, "value1");
200 EXPECT_NEAR(std::chrono::milliseconds(500).count(), expire_time.count(), kTIMING_TOLERANCE_MS);
201 // Add request @ value0 higher prio than value1
202 EXPECT_TRUE(t.AddRequest(0, "LAUNCH", start + 200ms));
203 expire_time = t.Update(true);
204 EXPECT_EQ(node_val, "value0");
205 EXPECT_NEAR(std::chrono::milliseconds(200).count(), expire_time.count(), kTIMING_TOLERANCE_MS);
206 // Add request @ value0 shorter
207 EXPECT_TRUE(t.AddRequest(0, "LAUNCH", start + 100ms));
208 expire_time = t.Update(true);
209 EXPECT_EQ(node_val, "value0");
210 EXPECT_NEAR(std::chrono::milliseconds(200).count(), expire_time.count(), kTIMING_TOLERANCE_MS);
211 // Add request @ value0 longer
212 EXPECT_TRUE(t.AddRequest(0, "LAUNCH", start + 300ms));
213 expire_time = t.Update(true);
214 EXPECT_EQ(node_val, "value0");
215 EXPECT_NEAR(std::chrono::milliseconds(300).count(), expire_time.count(), kTIMING_TOLERANCE_MS);
216 // Remove high prio request, now only request @ value1 active
217 t.RemoveRequest("LAUNCH");
218 expire_time = t.Update(true);
219 EXPECT_EQ(node_val, "value1");
220 EXPECT_NEAR(std::chrono::milliseconds(500).count(), expire_time.count(), kTIMING_TOLERANCE_MS);
221 // Remove request, now default value2
222 t.RemoveRequest("INTERACTION");
223 expire_time = t.Update(true);
224 EXPECT_EQ(node_val, "value2");
225 EXPECT_EQ(std::chrono::milliseconds::max(), expire_time);
226 }
227
228 } // namespace perfmgr
229 } // namespace android
230