1 /*
2 * Copyright (c) 2024, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <gtest/gtest.h>
30
31 #include <memory>
32 #include <string>
33
34 #include <openthread/error.h>
35
36 #include "common/code_utils.hpp"
37 #include "ncp/async_task.hpp"
38
39 using otbr::Ncp::AsyncTask;
40 using otbr::Ncp::AsyncTaskPtr;
41
TEST(AsyncTask,TestOneStep)42 TEST(AsyncTask, TestOneStep)
43 {
44 AsyncTaskPtr task;
45 AsyncTaskPtr step1;
46 int resultHandlerCalledTimes = 0;
47 int stepCount = 0;
48
49 auto errorHandler = [&resultHandlerCalledTimes](otError aError, const std::string &aErrorInfo) {
50 OTBR_UNUSED_VARIABLE(aError);
51 OTBR_UNUSED_VARIABLE(aErrorInfo);
52
53 resultHandlerCalledTimes++;
54 };
55
56 task = std::make_shared<AsyncTask>(errorHandler);
57 task->First([&stepCount, &step1](AsyncTaskPtr aNext) {
58 step1 = std::move(aNext);
59 stepCount++;
60 });
61 task->Run();
62
63 step1->SetResult(OT_ERROR_NONE, "Success");
64
65 EXPECT_EQ(resultHandlerCalledTimes, 1);
66 EXPECT_EQ(stepCount, 1);
67 }
68
TEST(AsyncTask,TestNoResultReturned)69 TEST(AsyncTask, TestNoResultReturned)
70 {
71 AsyncTaskPtr task;
72 AsyncTaskPtr step1;
73 AsyncTaskPtr step2;
74 AsyncTaskPtr step3;
75
76 int resultHandlerCalledTimes = 0;
77 int stepCount = 0;
78 otError error = OT_ERROR_NONE;
79
80 auto errorHandler = [&resultHandlerCalledTimes, &error](otError aError, const std::string &aErrorInfo) {
81 OTBR_UNUSED_VARIABLE(aErrorInfo);
82
83 resultHandlerCalledTimes++;
84 error = aError;
85 };
86
87 task = std::make_shared<AsyncTask>(errorHandler);
88 task->First([&stepCount, &step1](AsyncTaskPtr aNext) {
89 step1 = std::move(aNext);
90 stepCount++;
91 })
92 ->Then([&stepCount, &step2](AsyncTaskPtr aNext) {
93 step2 = std::move(aNext);
94 stepCount++;
95 })
96 ->Then([&stepCount, &step3](AsyncTaskPtr aNext) {
97 step3 = std::move(aNext);
98 stepCount++;
99 });
100 task->Run();
101
102 // Asyn task ends without calling 'SetResult'.
103 step1 = nullptr;
104 task = nullptr;
105
106 EXPECT_EQ(resultHandlerCalledTimes, 1);
107 EXPECT_EQ(stepCount, 1);
108 EXPECT_EQ(error, OT_ERROR_FAILED);
109 }
110
TEST(AsyncTask,TestMultipleStepsSuccess)111 TEST(AsyncTask, TestMultipleStepsSuccess)
112 {
113 AsyncTaskPtr task;
114 AsyncTaskPtr step1;
115 AsyncTaskPtr step2;
116 AsyncTaskPtr step3;
117
118 int resultHandlerCalledTimes = 0;
119 int stepCount = 0;
120 otError error = OT_ERROR_NONE;
121
122 auto errorHandler = [&resultHandlerCalledTimes, &error](otError aError, const std::string &aErrorInfo) {
123 OTBR_UNUSED_VARIABLE(aErrorInfo);
124
125 resultHandlerCalledTimes++;
126 error = aError;
127 };
128
129 task = std::make_shared<AsyncTask>(errorHandler);
130 task->First([&stepCount, &step1](AsyncTaskPtr aNext) {
131 step1 = std::move(aNext);
132 stepCount++;
133 })
134 ->Then([&stepCount, &step2](AsyncTaskPtr aNext) {
135 step2 = std::move(aNext);
136 stepCount++;
137 })
138 ->Then([&stepCount, &step3](AsyncTaskPtr aNext) {
139 step3 = std::move(aNext);
140 stepCount++;
141 });
142 task->Run();
143
144 EXPECT_EQ(stepCount, 1);
145 step1->SetResult(OT_ERROR_NONE, "");
146 EXPECT_EQ(resultHandlerCalledTimes, 0);
147
148 EXPECT_EQ(stepCount, 2);
149 step2->SetResult(OT_ERROR_NONE, "");
150 EXPECT_EQ(resultHandlerCalledTimes, 0);
151
152 EXPECT_EQ(stepCount, 3);
153 error = OT_ERROR_GENERIC;
154 step3->SetResult(OT_ERROR_NONE, "");
155 EXPECT_EQ(resultHandlerCalledTimes, 1);
156 EXPECT_EQ(error, OT_ERROR_NONE);
157 }
158
TEST(AsyncTask,TestMultipleStepsFailedHalfWay)159 TEST(AsyncTask, TestMultipleStepsFailedHalfWay)
160 {
161 AsyncTaskPtr task;
162 AsyncTaskPtr step1;
163 AsyncTaskPtr step2;
164 AsyncTaskPtr step3;
165
166 int resultHandlerCalledTimes = 0;
167 int stepCount = 0;
168 otError error = OT_ERROR_NONE;
169
170 auto errorHandler = [&resultHandlerCalledTimes, &error](otError aError, const std::string &aErrorInfo) {
171 OTBR_UNUSED_VARIABLE(aErrorInfo);
172
173 resultHandlerCalledTimes++;
174 error = aError;
175 };
176
177 task = std::make_shared<AsyncTask>(errorHandler);
178 task->First([&stepCount, &step1](AsyncTaskPtr aNext) {
179 step1 = std::move(aNext);
180 stepCount++;
181 })
182 ->Then([&stepCount, &step2](AsyncTaskPtr aNext) {
183 step2 = std::move(aNext);
184 stepCount++;
185 })
186 ->Then([&stepCount, &step3](AsyncTaskPtr aNext) {
187 step3 = std::move(aNext);
188 stepCount++;
189 });
190 task->Run();
191
192 EXPECT_EQ(stepCount, 1);
193 step1->SetResult(OT_ERROR_NONE, "");
194 EXPECT_EQ(resultHandlerCalledTimes, 0);
195
196 EXPECT_EQ(stepCount, 2);
197 step2->SetResult(OT_ERROR_BUSY, "");
198 EXPECT_EQ(resultHandlerCalledTimes, 1);
199 EXPECT_EQ(error, OT_ERROR_BUSY);
200 }
201