1/*
2 * Copyright (c) 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#include <chrono>
16#include <thread>
17#include <gtest/gtest.h>
18
19#include "service_control.h"
20#include "beget_ext.h"
21#include "test_utils.h"
22
23using namespace testing::ext;
24namespace initModuleTest {
25namespace {
26// Default wait for service status change time is 10 seconds
27constexpr int WAIT_SERVICE_STATUS_TIMEOUT = 10;
28}
29
30class ServiceControlTest : public testing::Test {
31public:
32    static void SetUpTestCase() {};
33    static void TearDownTestCase() {};
34    void SetUp() {};
35    void TearDown() {};
36};
37
38// Test service start
39HWTEST_F(ServiceControlTest, ServiceStartTest, TestSize.Level1)
40{
41    // Pick an unusual service for testing
42    // Try to start media_service.
43
44    // 1) Check if media_service exist
45    std::string serviceName = "media_service";
46    auto status = GetServiceStatus(serviceName);
47    if (status == "running") {
48        int ret = ServiceControl(serviceName.c_str(), STOP);
49        ASSERT_EQ(ret, 0);
50        ret = ServiceWaitForStatus(serviceName.c_str(), SERVICE_STOPPED, WAIT_SERVICE_STATUS_TIMEOUT);
51        ASSERT_EQ(ret, 0);
52    } else if (status != "created" && status != "stopped") {
53        std::cout << serviceName << " in invalid status " << status << std::endl;
54        std::cout << "Debug " << serviceName << " in unexpected status " << status << std::endl;
55        ASSERT_TRUE(0);
56    }
57
58    // 2) Now try to start service
59    int ret = ServiceControl(serviceName.c_str(), START);
60    EXPECT_EQ(ret, 0);
61    ret = ServiceWaitForStatus(serviceName.c_str(), SERVICE_STARTED, WAIT_SERVICE_STATUS_TIMEOUT);
62    EXPECT_EQ(ret, 0);
63    status = GetServiceStatus(serviceName);
64    std::cout << "Debug " << serviceName << " in status " << status << std::endl;
65    EXPECT_TRUE(status == "running");
66}
67
68HWTEST_F(ServiceControlTest, NonExistServiceStartTest, TestSize.Level1)
69{
70    std::string serviceName = "non_exist_service";
71    int ret = ServiceControl(serviceName.c_str(), START);
72    EXPECT_EQ(ret, 0); // No matter if service exist or not, ServiceControl always success.
73
74    auto status = GetServiceStatus(serviceName);
75    EXPECT_TRUE(status == "idle");
76}
77
78HWTEST_F(ServiceControlTest, ServiceStopTest, TestSize.Level1)
79{
80    std::string serviceName = "media_service";
81    auto status = GetServiceStatus(serviceName);
82    if (status == "stopped" || status == "created") {
83        int ret = ServiceControl(serviceName.c_str(), START);
84        ASSERT_EQ(ret, 0); // start must be success
85
86    } else if (status != "running") {
87        std::cout << serviceName << " in invalid status " << status << std::endl;
88        ASSERT_TRUE(0);
89    }
90
91    int ret = ServiceControl(serviceName.c_str(), STOP);
92    EXPECT_EQ(ret, 0);
93    // Sleep for a while, let init handle service starting.
94    const int64_t ms = 500;
95    std::this_thread::sleep_for(std::chrono::milliseconds(ms));
96    status = GetServiceStatus(serviceName);
97    bool isStopped = status == "stopped";
98    EXPECT_TRUE(isStopped);
99}
100
101HWTEST_F(ServiceControlTest, NonExistServiceStopTest, TestSize.Level1)
102{
103    std::string serviceName = "non_exist_service";
104    int ret = ServiceControl(serviceName.c_str(), STOP);
105    EXPECT_EQ(ret, 0); // No matter if service exist or not, ServiceControl always success.
106
107    auto status = GetServiceStatus(serviceName);
108    EXPECT_TRUE(status == "idle");
109}
110
111HWTEST_F(ServiceControlTest, ServiceTimerStartTest, TestSize.Level1)
112{
113    uint64_t timeout = 1000; // Start service in 1 second
114    std::string serviceName = "media_service";
115    // stop this service first
116    int ret = ServiceControl(serviceName.c_str(), STOP);
117    auto oldStatus = GetServiceStatus(serviceName);
118    bool isRunning = oldStatus == "running";
119    EXPECT_FALSE(isRunning);
120
121    ret = StartServiceByTimer(serviceName.c_str(), timeout);
122    EXPECT_EQ(ret, 0);
123
124    // Service will be started in @timeout seconds
125    // Now we try to sleep about @timeout / 2 seconds, then check service status.
126    int64_t ms = 600;
127    std::this_thread::sleep_for(std::chrono::milliseconds(ms));
128    // Get service status.
129    auto newStatus = GetServiceStatus(serviceName);
130    bool notChange = oldStatus == newStatus;
131    EXPECT_TRUE(notChange);
132
133    std::this_thread::sleep_for(std::chrono::milliseconds(ms));
134    newStatus = GetServiceStatus(serviceName);
135
136    isRunning = newStatus == "running";
137    EXPECT_TRUE(isRunning);
138}
139
140HWTEST_F(ServiceControlTest, ServiceTimerStartContinuouslyTest, TestSize.Level1)
141{
142    uint64_t oldTimeout = 500;
143    uint64_t newTimeout = 1000;
144    std::string serviceName = "media_service";
145    int ret = ServiceControl(serviceName.c_str(), STOP);
146    EXPECT_EQ(ret, 0);
147    ret = ServiceWaitForStatus(serviceName.c_str(), SERVICE_STOPPED, WAIT_SERVICE_STATUS_TIMEOUT);
148    EXPECT_EQ(ret, 0);
149    auto oldStatus = GetServiceStatus(serviceName);
150    bool isRunning = oldStatus == "running";
151    EXPECT_FALSE(isRunning);
152
153    ret = StartServiceByTimer(serviceName.c_str(), oldTimeout); // Set timer as 500 ms
154    EXPECT_EQ(ret, 0);
155    ret = StartServiceByTimer(serviceName.c_str(), newTimeout); // Set timer as 1 second
156    EXPECT_EQ(ret, 0);
157
158    std::this_thread::sleep_for(std::chrono::milliseconds(static_cast<int64_t>(oldTimeout)));
159    auto newStatus = GetServiceStatus(serviceName);
160    bool notChange = oldStatus == newStatus;
161    EXPECT_TRUE(notChange);
162    uint64_t margin = 20; // 20 ms margin in case of timer not that precisely
163    std::this_thread::sleep_for(std::chrono::milliseconds(static_cast<int64_t>(oldTimeout + margin)));
164    newStatus = GetServiceStatus(serviceName);
165    isRunning = newStatus == "running";
166    EXPECT_TRUE(isRunning);
167}
168
169HWTEST_F(ServiceControlTest, ServiceTimerStopTest, TestSize.Level1)
170{
171    uint64_t timeout = 1000; // set timer as 1 second
172    std::string serviceName = "media_service";
173    int ret = ServiceControl(serviceName.c_str(), STOP);
174    EXPECT_EQ(ret, 0);
175    ret = ServiceWaitForStatus(serviceName.c_str(), SERVICE_STOPPED, WAIT_SERVICE_STATUS_TIMEOUT);
176    EXPECT_EQ(ret, 0);
177    auto oldStatus = GetServiceStatus(serviceName);
178    bool isRunning = oldStatus == "running";
179    EXPECT_FALSE(isRunning);
180
181    ret = StartServiceByTimer(serviceName.c_str(), timeout);
182    EXPECT_EQ(ret, 0);
183
184    // Now sleep for a while
185    int64_t ms = 300;
186    std::this_thread::sleep_for(std::chrono::milliseconds(ms));
187    auto newStatus = GetServiceStatus(serviceName);
188
189    bool notChange = oldStatus == newStatus;
190    EXPECT_TRUE(notChange);
191
192    ret = StopServiceTimer(serviceName.c_str());
193    EXPECT_EQ(ret, 0);
194    std::this_thread::sleep_for(std::chrono::milliseconds(ms));
195
196    newStatus = GetServiceStatus(serviceName);
197    notChange = oldStatus == newStatus;
198    EXPECT_TRUE(notChange);
199}
200
201HWTEST_F(ServiceControlTest, ServiceTimerStopLateTest, TestSize.Level1)
202{
203    uint64_t timeout = 500; // set timer as 5 micro seconds
204    std::string serviceName = "media_service";
205    int ret = ServiceControl(serviceName.c_str(), STOP);
206    auto oldStatus = GetServiceStatus(serviceName);
207    bool isRunning = oldStatus == "running";
208    EXPECT_FALSE(isRunning);
209
210    ret = StartServiceByTimer(serviceName.c_str(), timeout);
211    EXPECT_EQ(ret, 0);
212
213    int64_t ms = 550;
214    std::this_thread::sleep_for(std::chrono::milliseconds(ms));
215    ret = StopServiceTimer(serviceName.c_str());
216    EXPECT_EQ(ret, 0);
217
218    auto newStatus = GetServiceStatus(serviceName);
219    isRunning = newStatus == "running";
220    EXPECT_TRUE(isRunning);
221}
222
223HWTEST_F(ServiceControlTest, RestartServiceTest, TestSize.Level1)
224{
225    std::string serviceName = "media_service";
226    auto status = GetServiceStatus(serviceName);
227    EXPECT_FALSE(status.empty());
228
229    int ret = ServiceControl(serviceName.c_str(), RESTART);
230    EXPECT_EQ(ret, 0);
231
232    ret = ServiceControl(serviceName.c_str(), STOP);
233    EXPECT_EQ(ret, 0);
234
235    ret = ServiceWaitForStatus(serviceName.c_str(), SERVICE_STOPPED, WAIT_SERVICE_STATUS_TIMEOUT);
236    EXPECT_EQ(ret, 0);
237
238    ret = ServiceControl(serviceName.c_str(), RESTART);
239    EXPECT_EQ(ret, 0);
240
241    status = GetServiceStatus(serviceName);
242
243    bool isRunning = status == "running";
244    EXPECT_TRUE(isRunning);
245}
246
247HWTEST_F(ServiceControlTest, WaitForServiceStatusTest, TestSize.Level1)
248{
249    std::string serviceName = "media_service";
250    int ret = ServiceControl(serviceName.c_str(), STOP);
251    EXPECT_EQ(ret, 0);
252
253    ret = ServiceWaitForStatus(serviceName.c_str(), SERVICE_STOPPED, WAIT_SERVICE_STATUS_TIMEOUT);
254    EXPECT_EQ(ret, 0);
255
256    auto status = GetServiceStatus(serviceName);
257    bool isStopped = status == "stopped";
258    EXPECT_TRUE(isStopped);
259
260    // service is stopped now. try to wait a status which will not be set
261    std::cout << "Wait for service " << serviceName << " status change to start\n";
262    ret = ServiceWaitForStatus(serviceName.c_str(), SERVICE_STARTED, WAIT_SERVICE_STATUS_TIMEOUT);
263    BEGET_ERROR_CHECK(ret == -1, return, "Get media_service status failed.");
264
265    serviceName = "non-exist-service";
266    std::cout << "Wait for service " << serviceName << " status change to stop\n";
267    ret = ServiceWaitForStatus(serviceName.c_str(), SERVICE_STOPPED, WAIT_SERVICE_STATUS_TIMEOUT);
268    EXPECT_EQ(ret, -1);
269}
270} // initModuleTest
271