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