summaryrefslogtreecommitdiffstats
path: root/xbmc/utils/test/TestJobManager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/utils/test/TestJobManager.cpp')
-rw-r--r--xbmc/utils/test/TestJobManager.cpp215
1 files changed, 215 insertions, 0 deletions
diff --git a/xbmc/utils/test/TestJobManager.cpp b/xbmc/utils/test/TestJobManager.cpp
new file mode 100644
index 0000000..40165e9
--- /dev/null
+++ b/xbmc/utils/test/TestJobManager.cpp
@@ -0,0 +1,215 @@
1/*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
8
9#include "test/MtTestUtils.h"
10#include "utils/Job.h"
11#include "utils/JobManager.h"
12#include "utils/XTimeUtils.h"
13
14#include <atomic>
15
16#include <gtest/gtest.h>
17
18using namespace ConditionPoll;
19
20struct Flags
21{
22 std::atomic<bool> lingerAtWork{true};
23 std::atomic<bool> started{false};
24 std::atomic<bool> finished{false};
25 std::atomic<bool> wasCanceled{false};
26};
27
28class DummyJob : public CJob
29{
30 Flags* m_flags;
31public:
32 inline DummyJob(Flags* flags) : m_flags(flags)
33 {
34 }
35
36 bool DoWork() override
37 {
38 m_flags->started = true;
39 while (m_flags->lingerAtWork)
40 std::this_thread::yield();
41
42 if (ShouldCancel(0,0))
43 m_flags->wasCanceled = true;
44
45 m_flags->finished = true;
46 return true;
47 }
48};
49
50class ReallyDumbJob : public CJob
51{
52 Flags* m_flags;
53public:
54 inline ReallyDumbJob(Flags* flags) : m_flags(flags) {}
55
56 bool DoWork() override
57 {
58 m_flags->finished = true;
59 return true;
60 }
61};
62
63class TestJobManager : public testing::Test
64{
65protected:
66 TestJobManager() = default;
67
68 ~TestJobManager() override
69 {
70 /* Always cancel jobs test completion */
71 CJobManager::GetInstance().CancelJobs();
72 CJobManager::GetInstance().Restart();
73 }
74};
75
76TEST_F(TestJobManager, AddJob)
77{
78 Flags* flags = new Flags();
79 ReallyDumbJob* job = new ReallyDumbJob(flags);
80 CJobManager::GetInstance().AddJob(job, NULL);
81 ASSERT_TRUE(poll([flags]() -> bool { return flags->finished; }));
82 delete flags;
83}
84
85TEST_F(TestJobManager, CancelJob)
86{
87 unsigned int id;
88 Flags* flags = new Flags();
89 DummyJob* job = new DummyJob(flags);
90 id = CJobManager::GetInstance().AddJob(job, NULL);
91
92 // wait for the worker thread to be entered
93 ASSERT_TRUE(poll([flags]() -> bool { return flags->started; }));
94
95 // cancel the job
96 CJobManager::GetInstance().CancelJob(id);
97
98 // let the worker thread continue
99 flags->lingerAtWork = false;
100
101 // make sure the job finished.
102 ASSERT_TRUE(poll([flags]() -> bool { return flags->finished; }));
103
104 // ... and that it was canceled.
105 EXPECT_TRUE(flags->wasCanceled);
106 delete flags;
107}
108
109namespace
110{
111struct JobControlPackage
112{
113 JobControlPackage()
114 {
115 // We're not ready to wait yet
116 jobCreatedMutex.lock();
117 }
118
119 ~JobControlPackage()
120 {
121 jobCreatedMutex.unlock();
122 }
123
124 bool ready = false;
125 XbmcThreads::ConditionVariable jobCreatedCond;
126 CCriticalSection jobCreatedMutex;
127};
128
129class BroadcastingJob :
130 public CJob
131{
132public:
133
134 BroadcastingJob(JobControlPackage &package) :
135 m_package(package),
136 m_finish(false)
137 {
138 }
139
140 void FinishAndStopBlocking()
141 {
142 CSingleLock lock(m_blockMutex);
143
144 m_finish = true;
145 m_block.notifyAll();
146 }
147
148 const char * GetType() const override
149 {
150 return "BroadcastingJob";
151 }
152
153 bool DoWork() override
154 {
155 {
156 CSingleLock lock(m_package.jobCreatedMutex);
157
158 m_package.ready = true;
159 m_package.jobCreatedCond.notifyAll();
160 }
161
162 CSingleLock blockLock(m_blockMutex);
163
164 // Block until we're told to go away
165 while (!m_finish)
166 m_block.wait(m_blockMutex);
167 return true;
168 }
169
170private:
171
172 JobControlPackage &m_package;
173
174 XbmcThreads::ConditionVariable m_block;
175 CCriticalSection m_blockMutex;
176 bool m_finish;
177};
178
179BroadcastingJob *
180WaitForJobToStartProcessing(CJob::PRIORITY priority, JobControlPackage &package)
181{
182 BroadcastingJob* job = new BroadcastingJob(package);
183 CJobManager::GetInstance().AddJob(job, NULL, priority);
184
185 // We're now ready to wait, wait and then unblock once ready
186 while (!package.ready)
187 package.jobCreatedCond.wait(package.jobCreatedMutex);
188
189 return job;
190}
191}
192
193TEST_F(TestJobManager, PauseLowPriorityJob)
194{
195 JobControlPackage package;
196 BroadcastingJob *job (WaitForJobToStartProcessing(CJob::PRIORITY_LOW_PAUSABLE, package));
197
198 EXPECT_TRUE(CJobManager::GetInstance().IsProcessing(CJob::PRIORITY_LOW_PAUSABLE));
199 CJobManager::GetInstance().PauseJobs();
200 EXPECT_FALSE(CJobManager::GetInstance().IsProcessing(CJob::PRIORITY_LOW_PAUSABLE));
201 CJobManager::GetInstance().UnPauseJobs();
202 EXPECT_TRUE(CJobManager::GetInstance().IsProcessing(CJob::PRIORITY_LOW_PAUSABLE));
203
204 job->FinishAndStopBlocking();
205}
206
207TEST_F(TestJobManager, IsProcessing)
208{
209 JobControlPackage package;
210 BroadcastingJob *job (WaitForJobToStartProcessing(CJob::PRIORITY_LOW_PAUSABLE, package));
211
212 EXPECT_EQ(0, CJobManager::GetInstance().IsProcessing(""));
213
214 job->FinishAndStopBlocking();
215}