1 /*
2 * Copyright (C) 2019 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 <binder/app_launch_event.h>
18
19 #include <gtest/gtest.h>
20
21 // TODO: move to app_launch_event.h
22 #include <google/protobuf/util/message_differencer.h>
23
24 using namespace iorap::binder; // NOLINT
25
26 using android::Parcel;
27
28 using Type = AppLaunchEvent::Type;
29 using Temperature = AppLaunchEvent::Temperature;
30
31 namespace iorap::binder {
32
ProtosEqual(const::google::protobuf::Message & lhs,const::google::protobuf::Message & rhs)33 inline bool ProtosEqual(const ::google::protobuf::Message& lhs,
34 const ::google::protobuf::Message& rhs) {
35 return ::google::protobuf::util::MessageDifferencer::Equals(lhs, rhs);
36 }
37
ProtosEqual(const::google::protobuf::MessageLite & lhs,const::google::protobuf::MessageLite & rhs)38 inline bool ProtosEqual(const ::google::protobuf::MessageLite& lhs,
39 const ::google::protobuf::MessageLite& rhs) {
40 // MessageLite does not support 'MessageDifferencer' which requires protobuf-full
41 // because it uses reflection.
42 //
43 // Serialize as a string and compare. This may lead to false inequality when protobufs
44 // are actually the same but their encodings are slightly different.
45 return lhs.GetTypeName() == rhs.GetTypeName()
46 && lhs.SerializeAsString() == rhs.SerializeAsString();
47 }
48
49 template <typename T>
ProtoPointersEqual(const T & lhs_ptr,const T & rhs_ptr)50 inline bool ProtoPointersEqual(const T& lhs_ptr, const T& rhs_ptr) {
51 if (lhs_ptr == nullptr && rhs_ptr == nullptr) {
52 return true;
53 }
54 else if (lhs_ptr != nullptr && rhs_ptr != nullptr) {
55 return ProtosEqual(*lhs_ptr, *rhs_ptr);
56 }
57 return false;
58 }
59
60 // Field-by-field equality.
61 // Protos are compared according by checking that their serialized encodings are the same.
operator ==(const AppLaunchEvent & lhs,const AppLaunchEvent & rhs)62 inline bool operator==(const AppLaunchEvent& lhs, const AppLaunchEvent& rhs) {
63 # define EQ_OR_RETURN(l, r, val) if (!(l.val == r.val)) { return false; }
64 # define PROTO_EQ_OR_RETURN(l, r, val) if (!ProtoPointersEqual(l.val, r.val)) { return false; }
65
66 EQ_OR_RETURN(lhs, rhs, type);
67 EQ_OR_RETURN(lhs, rhs, sequence_id);
68 PROTO_EQ_OR_RETURN(lhs, rhs, intent_proto);
69 EQ_OR_RETURN(lhs, rhs, temperature);
70 PROTO_EQ_OR_RETURN(lhs, rhs, activity_record_proto);
71
72 # undef EQ_OR_RETURN
73 # undef PROTO_EQ_OR_RETURN
74
75 return true;
76 }
77
operator !=(const AppLaunchEvent & lhs,const AppLaunchEvent & rhs)78 inline bool operator!=(const AppLaunchEvent& lhs, const AppLaunchEvent& rhs) {
79 return !(lhs == rhs);
80 }
81
MakeIntentStarted(int64_t sequence_id,std::unique_ptr<IntentProto> intent_proto)82 static AppLaunchEvent MakeIntentStarted(int64_t sequence_id,
83 // non-null
84 std::unique_ptr<IntentProto> intent_proto) {
85 DCHECK(intent_proto != nullptr);
86
87 AppLaunchEvent e{Type::kIntentStarted, sequence_id, std::move(intent_proto)};
88 return e;
89 }
90
MakeIntentFailed(int64_t sequence_id)91 static AppLaunchEvent MakeIntentFailed(int64_t sequence_id) {
92 AppLaunchEvent e{Type::kIntentFailed, sequence_id};
93 return e;
94 }
95
96 static AppLaunchEvent
MakeActivityLaunched(int64_t sequence_id,Temperature temperature,std::unique_ptr<ActivityRecordProto> activity_record_proto)97 MakeActivityLaunched(int64_t sequence_id,
98 Temperature temperature,
99 // non-null
100 std::unique_ptr<ActivityRecordProto> activity_record_proto) {
101 DCHECK(activity_record_proto != nullptr);
102
103 AppLaunchEvent e{Type::kActivityLaunched,
104 sequence_id,
105 /*intent_proto*/nullptr,
106 temperature,
107 std::move(activity_record_proto)};
108 return e;
109 }
110
111 static AppLaunchEvent
MakeActivityLaunchCancelled(int64_t sequence_id,std::unique_ptr<ActivityRecordProto> activity_record_proto=nullptr)112 MakeActivityLaunchCancelled(int64_t sequence_id,
113 // nullable
114 std::unique_ptr<ActivityRecordProto> activity_record_proto = nullptr) {
115 AppLaunchEvent e{Type::kActivityLaunchCancelled,
116 sequence_id,
117 /*intent_proto*/nullptr,
118 Temperature::kUninitialized,
119 std::move(activity_record_proto)};
120 return e;
121 }
122
123 static AppLaunchEvent
MakeActivityLaunchFinished(int64_t sequence_id,std::unique_ptr<ActivityRecordProto> activity_record_proto)124 MakeActivityLaunchFinished(int64_t sequence_id,
125 // non-null
126 std::unique_ptr<ActivityRecordProto> activity_record_proto) {
127 DCHECK(activity_record_proto != nullptr);
128 AppLaunchEvent e{Type::kActivityLaunchFinished,
129 sequence_id,
130 /*intent_proto*/nullptr,
131 Temperature::kUninitialized,
132 std::move(activity_record_proto)};
133 return e;
134 }
135
136 } // namespace iorap::binder
137
MakeDummyIntent(std::string action="package_name/.ClassName")138 auto MakeDummyIntent(std::string action = "package_name/.ClassName") {
139 std::unique_ptr<IntentProto> dummy_intent{new IntentProto{}};
140 dummy_intent->set_action(action);
141 return dummy_intent;
142 }
143
MakeDummyActivityRecord(std::string title="package_name/.ClassName")144 auto MakeDummyActivityRecord(std::string title = "package_name/.ClassName") {
145 std::unique_ptr<ActivityRecordProto> dummy{new ActivityRecordProto{}};
146
147 dummy->mutable_identifier()->set_title(title);
148
149 return dummy;
150 }
151
TEST(AppLaunchEventTest,Equals)152 TEST(AppLaunchEventTest, Equals) {
153 EXPECT_EQ(MakeIntentStarted(456, MakeDummyIntent()), MakeIntentStarted(456, MakeDummyIntent()));
154 EXPECT_NE(MakeIntentStarted(45, MakeDummyIntent()), MakeIntentStarted(45, MakeDummyIntent("a")));
155
156 EXPECT_EQ(MakeIntentFailed(123), MakeIntentFailed(123));
157 EXPECT_NE(MakeIntentFailed(0), MakeIntentFailed(123));
158
159 EXPECT_EQ((MakeActivityLaunched(3, Temperature::kHot, MakeDummyActivityRecord())),
160 (MakeActivityLaunched(3, Temperature::kHot, MakeDummyActivityRecord())));
161 EXPECT_NE((MakeActivityLaunched(3, Temperature::kHot, MakeDummyActivityRecord())),
162 (MakeActivityLaunched(3, Temperature::kCold, MakeDummyActivityRecord())));
163 EXPECT_NE((MakeActivityLaunched(3, Temperature::kHot, MakeDummyActivityRecord())),
164 (MakeActivityLaunched(3, Temperature::kHot, MakeDummyActivityRecord("other title"))));
165
166 EXPECT_EQ((MakeActivityLaunchCancelled(4)),
167 (MakeActivityLaunchCancelled(4)));
168 EXPECT_EQ((MakeActivityLaunchCancelled(4, MakeDummyActivityRecord())),
169 (MakeActivityLaunchCancelled(4, MakeDummyActivityRecord())));
170 EXPECT_NE((MakeActivityLaunchCancelled(4, MakeDummyActivityRecord())),
171 (MakeActivityLaunchCancelled(4, MakeDummyActivityRecord("other"))));
172 EXPECT_NE((MakeActivityLaunchCancelled(4, MakeDummyActivityRecord())),
173 (MakeActivityLaunchCancelled(4)));
174
175 EXPECT_EQ((MakeActivityLaunchFinished(5, MakeDummyActivityRecord())),
176 (MakeActivityLaunchFinished(5, MakeDummyActivityRecord())));
177 EXPECT_NE((MakeActivityLaunchFinished(5, MakeDummyActivityRecord())),
178 (MakeActivityLaunchFinished(5, MakeDummyActivityRecord("other title"))));
179 }
180
181 template <typename T>
ValueParcelRoundTrip(const T & value)182 T ValueParcelRoundTrip(const T& value) {
183 ::android::Parcel p;
184 CHECK_EQ(value.writeToParcel(&p), ::android::NO_ERROR);
185
186 T new_value;
187 p.setDataPosition(0);
188 CHECK_EQ(new_value.readFromParcel(&p), ::android::NO_ERROR);
189
190 return new_value;
191 }
192
193 #define EXPECT_PARCELING_ROUND_TRIP(a) EXPECT_EQ((a), ValueParcelRoundTrip((a)))
194
TEST(AppLaunchEventTest,ParcelingRoundTrip)195 TEST(AppLaunchEventTest, ParcelingRoundTrip) {
196 EXPECT_PARCELING_ROUND_TRIP(MakeIntentStarted(456, MakeDummyIntent()));
197 EXPECT_PARCELING_ROUND_TRIP(MakeIntentFailed(123));
198 EXPECT_PARCELING_ROUND_TRIP(MakeActivityLaunched(3, Temperature::kHot, MakeDummyActivityRecord()));
199 EXPECT_PARCELING_ROUND_TRIP(MakeActivityLaunchCancelled(4));
200 EXPECT_PARCELING_ROUND_TRIP(MakeActivityLaunchCancelled(4, MakeDummyActivityRecord()));
201 EXPECT_PARCELING_ROUND_TRIP(MakeActivityLaunchFinished(5, MakeDummyActivityRecord()));
202 }
203