1 /*
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <utility>
17
18 #include "gtest/gtest.h"
19 #include "extern_api.h"
20 #include "widget_selector.h"
21
22 using namespace OHOS::uitest;
23 using namespace std;
24 using namespace nlohmann;
25
26 // test fixture
27 class ExternApiTest : public testing::Test {
28 public:
29 ~ExternApiTest() override = default;
30 };
31
32 class DummyApi : public ExternApi<TypeId::BY> {
33 public:
DummyApi(string_view val)34 explicit DummyApi(string_view val) : value_(val) {};
35
36 ~ DummyApi() = default;
37
WriteIntoParcel(json & data) const38 void WriteIntoParcel(json &data) const override
39 {
40 data["value"] = value_;
41 }
42
ReadFromParcel(const json & data)43 void ReadFromParcel(const json &data) override
44 {
45 value_ = data["value"];
46 }
47
48 string value_;
49 };
50
TEST_F(ExternApiTest,readWriteParcelable)51 TEST_F(ExternApiTest, readWriteParcelable)
52 {
53 json container;
54 // write
55 PushBackValueItemIntoJson<string>("wyz", container);
56 PushBackValueItemIntoJson<int32_t>(666, container);
57 PushBackValueItemIntoJson<float>(0.2f, container);
58 PushBackValueItemIntoJson<bool>(true, container);
59 auto obj = DummyApi("zl");
60 PushBackValueItemIntoJson<DummyApi>(obj, container);
61 // read
62 auto val0 = GetItemValueFromJson<string>(container, 0);
63 auto val1 = GetItemValueFromJson<int32_t>(container, 1);
64 auto val2 = GetItemValueFromJson<float>(container, 2);
65 auto val3 = GetItemValueFromJson<bool>(container, 3);
66 auto val4 = GetItemValueFromJson<json>(container, 4);
67 // verify
68 ASSERT_EQ("wyz", val0);
69 ASSERT_EQ(666, val1);
70 ASSERT_EQ(0.2f, val2);
71 ASSERT_EQ(true, val3);
72 ASSERT_EQ("zl", val4["value"]);
73 }
74
GenerateUniqueId()75 static string GenerateUniqueId()
76 {
77 return to_string(GetCurrentMicroseconds());
78 }
79
TEST_F(ExternApiTest,noInvocationHandler)80 TEST_F(ExternApiTest, noInvocationHandler)
81 {
82 static auto apiId = GenerateUniqueId();
83 auto& server = ExternApiServer::Get();
84 json caller;
85 auto in = json::array();
86 auto out = json::array();
87 auto err = ApiCallErr(NO_ERROR);
88 server.Call(apiId, caller, in, out, err);
89 ASSERT_EQ(INTERNAL_ERROR, err.code_);
90 ASSERT_TRUE(err.message_.find("No handler found") != string::npos);
91 }
92
TEST_F(ExternApiTest,addRemoveHandler)93 TEST_F(ExternApiTest, addRemoveHandler)
94 {
95 static auto apiId = GenerateUniqueId();
96 auto &server = ExternApiServer::Get();
97 auto handler = [](string_view fun, json &caller, const json &in, json &out, ApiCallErr &err) {
98 if (fun == apiId) {
99 return true;
100 }
101 return false;
102 };
103 server.AddHandler(handler);
104
105 json caller;
106 auto in = json::array();
107 auto out = json::array();
108 auto err = ApiCallErr(NO_ERROR);
109 server.Call(apiId, caller, in, out, err);
110 ASSERT_EQ(NO_ERROR, err.code_);
111
112 server.RemoveHandler(handler);
113 server.Call(apiId, caller, in, out, err);
114 ASSERT_EQ(INTERNAL_ERROR, err.code_) << "The handler should be unavailable after been removed";
115 }
116
TEST_F(ExternApiTest,inOutObjectsTransfer)117 TEST_F(ExternApiTest, inOutObjectsTransfer)
118 {
119 static auto apiId = GenerateUniqueId();
120 auto& server = ExternApiServer::Get();
121 auto handler = [](string_view fun, json &caller, const json &in, json &out, ApiCallErr &err) {
122 if (fun == apiId) {
123 // write back the parameter value
124 PushBackValueItemIntoJson<int32_t>(GetItemValueFromJson<int32_t>(in, 0), out);
125 return true;
126 }
127 return false;
128 };
129 server.AddHandler(handler);
130
131 json caller;
132 auto in0 = json::array();
133 auto in1 = json::array();
134 auto out0 = json::array();
135 auto out1 = json::array();
136 auto err = ApiCallErr(NO_ERROR);
137 PushBackValueItemIntoJson<int32_t>(0, in0);
138 PushBackValueItemIntoJson<int32_t>(1, in1);
139 server.Call(apiId, caller, in0, out0, err);
140 // api request should be handled and get correct return value
141 ASSERT_EQ(NO_ERROR, err.code_);std::cout<<out0.dump()<<std::endl;
142 ASSERT_EQ(0, GetItemValueFromJson<int32_t>(out0, 0));
143 server.Call(apiId, caller, in1, out1, err);
144 ASSERT_EQ(NO_ERROR, err.code_);
145 ASSERT_EQ(1, GetItemValueFromJson<int32_t>(out1, 0));
146 }
147
TEST_F(ExternApiTest,jsonExceptionDefance)148 TEST_F(ExternApiTest, jsonExceptionDefance)
149 {
150 static auto apiId = GenerateUniqueId();
151 auto& server = ExternApiServer::Get();
152 auto handler = [](string_view fun, json &caller, const json &in, json &out, ApiCallErr &err) {
153 if (fun == apiId) {
154 // this statement will cause out-of-index exception
155 int32_t val0 = in.at(100);
156 return val0 > 0;
157 }
158 return false;
159 };
160 server.AddHandler(handler);
161
162 json caller;
163 auto in = json::array();
164 auto out = json::array();
165 auto err = ApiCallErr(NO_ERROR);
166 server.Call(apiId, caller, in, out, err);
167 // json exception should be caught and reported properly
168 ASSERT_EQ(INTERNAL_ERROR, err.code_);
169 ASSERT_TRUE(err.message_.find("Exception raised") != string::npos);
170 ASSERT_TRUE(err.message_.find("json.exception.out_of_range") != string::npos);
171 }
172
TEST_F(ExternApiTest,apiErrorDeliver)173 TEST_F(ExternApiTest, apiErrorDeliver)
174 {
175 static auto apiId = GenerateUniqueId();
176 auto& server = ExternApiServer::Get();
177 auto handler = [](string_view fun, json &caller, const json &in, json &out, ApiCallErr &err) {
178 if (fun == apiId) {
179 // this statement will cause out-of-index exception
180 int32_t val0 = GetItemValueFromJson<int32_t>(in, 0);
181 if (val0 == 0) {
182 err = ApiCallErr(NO_ERROR);
183 } else {
184 err = ApiCallErr(INTERNAL_ERROR, "dummy_error");
185 }
186 return true;
187 }
188 return false;
189 };
190 server.AddHandler(handler);
191
192 json caller;
193 auto in0 = json::array();
194 PushBackValueItemIntoJson<int32_t>(0, in0);
195 auto in1 = json::array();
196 PushBackValueItemIntoJson<int32_t>(1, in1);
197 auto out = json::array();
198 auto err = ApiCallErr(NO_ERROR);
199
200 server.Call(apiId, caller, in0, out, err);
201 ASSERT_EQ(NO_ERROR, err.code_) << err.message_;
202 server.Call(apiId, caller, in1, out, err);
203 // api error should be delivered out to caller
204 ASSERT_EQ(INTERNAL_ERROR, err.code_);
205 ASSERT_TRUE(err.message_.find("dummy_error") != string::npos);
206 }
207
TEST_F(ExternApiTest,stopDispatchingToRestHandlersAfterHandled)208 TEST_F(ExternApiTest, stopDispatchingToRestHandlersAfterHandled)
209 {
210 auto& server = ExternApiServer::Get();
211 auto handler0 = [](string_view fun, json &caller, const json &in, json &out, ApiCallErr &err) {
212 PushBackValueItemIntoJson<int32_t>(0, out);
213 if (fun != "api0") {
214 return false;
215 }
216 return true;
217 };
218 auto handler1 = [](string_view fun, json &caller, const json &in, json &out, ApiCallErr &err) {
219 PushBackValueItemIntoJson<int32_t>(1, out);
220 if (fun != "api1") {
221 return false;
222 }
223 auto param0 = GetItemValueFromJson<string>(in, 0);
224 if (param0 == "good") {
225 err = ApiCallErr(NO_ERROR);
226 } else {
227 err = ApiCallErr(INTERNAL_ERROR, "not good");
228 }
229 return true;
230 };
231 auto handler2 = [](string_view fun, json &caller, const json &in, json &out, ApiCallErr &err) {
232 PushBackValueItemIntoJson<int32_t>(2, out);
233 return fun == "api2";
234 };
235 server.AddHandler(handler0);
236 server.AddHandler(handler1);
237 server.AddHandler(handler2);
238
239 json caller;
240 auto in = json::array();
241 auto out = json::array();
242 auto err = ApiCallErr(NO_ERROR);
243 PushBackValueItemIntoJson<string>("good", in);
244 server.Call("api1", caller, in, out, err);
245 // Request should not be dispatched to handler2, since its served with by handler1
246 ASSERT_EQ(2, out.size());
247 ASSERT_EQ(NO_ERROR, err.code_);
248 ASSERT_EQ(0, GetItemValueFromJson<int32_t>(out, 0));
249 ASSERT_EQ(1, GetItemValueFromJson<int32_t>(out, 1));
250 in.clear();
251 out.clear();
252 PushBackValueItemIntoJson<string>("bad", in);
253 server.Call("api1", caller, in, out, err);
254 // Request should not be dispatched to handler2, since its served with by handler1, even though error happened
255 ASSERT_EQ(2, out.size());
256 ASSERT_EQ(INTERNAL_ERROR, err.code_);
257 ASSERT_EQ(0, GetItemValueFromJson<int32_t>(out, 0));
258 ASSERT_EQ(1, GetItemValueFromJson<int32_t>(out, 1));
259 }
260
TEST_F(ExternApiTest,apiTransactE2E)261 TEST_F(ExternApiTest, apiTransactE2E)
262 {
263 static auto apiId = GenerateUniqueId();
264 auto& server = ExternApiServer::Get();
265 auto handler = [](string_view fun, json &caller, const json &in, json &out, ApiCallErr &err) {
266 if (fun != apiId) {
267 return false;
268 }
269 PushBackValueItemIntoJson<int32_t>(0, out);
270 return true;
271 };
272 server.AddHandler(handler);
273
274 string resultStr = ApiTransact(apiId, "{}", "[]");
275 auto result = json::parse(resultStr);
276 ASSERT_FALSE(result.contains("exception"));
277 ASSERT_TRUE(result.contains("result_values"));
278 ASSERT_NE(0, result["result_values"].size()) << resultStr; // should have result values
279 }
280
TEST_F(ExternApiTest,apiTransactE2EFailure)281 TEST_F(ExternApiTest, apiTransactE2EFailure)
282 {
283 static auto apiId = GenerateUniqueId();
284 auto &server = ExternApiServer::Get();
285 auto handler = [](string_view fun, json &caller, const json &in, json &out, ApiCallErr &err) {
286 if (fun != apiId) {
287 return false;
288 }
289 PushBackValueItemIntoJson<int32_t>(0, out);
290 return true;
291 };
292 server.AddHandler(handler);
293
294 string resultStr = ApiTransact("foo", "{}", "[]"); // api not-found
295 auto result = json::parse(resultStr);
296 ASSERT_TRUE(result.contains("exception")) << "Transact failure should be delivered in the results";
297 }