1 | #include "test.h" |
2 | #include <gtest/gtest.h> |
3 | |
4 | #include <base/system.h> |
5 | |
6 | #include <engine/shared/host_lookup.h> |
7 | #include <engine/shared/jobs.h> |
8 | |
9 | #include <functional> |
10 | |
11 | static const int TEST_NUM_THREADS = 4; |
12 | |
13 | class Jobs : public ::testing::Test |
14 | { |
15 | protected: |
16 | CJobPool m_Pool; |
17 | |
18 | void SetUp() override |
19 | { |
20 | m_Pool.Init(NumThreads: TEST_NUM_THREADS); |
21 | } |
22 | |
23 | void TearDown() override |
24 | { |
25 | m_Pool.Shutdown(); |
26 | } |
27 | |
28 | void Add(std::shared_ptr<IJob> pJob) |
29 | { |
30 | m_Pool.Add(pJob: std::move(pJob)); |
31 | } |
32 | }; |
33 | |
34 | class CJob : public IJob |
35 | { |
36 | std::function<void()> m_JobFunction; |
37 | void Run() override { m_JobFunction(); } |
38 | |
39 | public: |
40 | CJob(std::function<void()> &&JobFunction) : |
41 | m_JobFunction(JobFunction) {} |
42 | |
43 | void Abortable(bool Abortable) |
44 | { |
45 | IJob::Abortable(Abortable); |
46 | } |
47 | }; |
48 | |
49 | TEST_F(Jobs, Constructor) |
50 | { |
51 | } |
52 | |
53 | TEST_F(Jobs, Simple) |
54 | { |
55 | Add(pJob: std::make_shared<CJob>(args: [] {})); |
56 | } |
57 | |
58 | TEST_F(Jobs, Wait) |
59 | { |
60 | SEMAPHORE sphore; |
61 | sphore_init(sem: &sphore); |
62 | Add(pJob: std::make_shared<CJob>(args: [&] { sphore_signal(sem: &sphore); })); |
63 | sphore_wait(sem: &sphore); |
64 | sphore_destroy(sem: &sphore); |
65 | } |
66 | |
67 | TEST_F(Jobs, AbortAbortable) |
68 | { |
69 | auto pJob = std::make_shared<CJob>(args: [&] {}); |
70 | pJob->Abortable(Abortable: true); |
71 | EXPECT_TRUE(pJob->IsAbortable()); |
72 | Add(pJob); |
73 | EXPECT_TRUE(pJob->Abort()); |
74 | EXPECT_EQ(pJob->State(), IJob::STATE_ABORTED); |
75 | } |
76 | |
77 | TEST_F(Jobs, AbortUnabortable) |
78 | { |
79 | auto pJob = std::make_shared<CJob>(args: [&] {}); |
80 | pJob->Abortable(Abortable: false); |
81 | EXPECT_FALSE(pJob->IsAbortable()); |
82 | Add(pJob); |
83 | EXPECT_FALSE(pJob->Abort()); |
84 | EXPECT_NE(pJob->State(), IJob::STATE_ABORTED); |
85 | } |
86 | |
87 | TEST_F(Jobs, LookupHost) |
88 | { |
89 | static const char *HOST = "example.com" ; |
90 | static const int NETTYPE = NETTYPE_ALL; |
91 | auto pJob = std::make_shared<CHostLookup>(args&: HOST, args: NETTYPE); |
92 | |
93 | EXPECT_STREQ(pJob->Hostname(), HOST); |
94 | EXPECT_EQ(pJob->Nettype(), NETTYPE); |
95 | |
96 | Add(pJob); |
97 | while(pJob->State() != IJob::STATE_DONE) |
98 | { |
99 | // yay, busy loop... |
100 | thread_yield(); |
101 | } |
102 | |
103 | EXPECT_STREQ(pJob->Hostname(), HOST); |
104 | EXPECT_EQ(pJob->Nettype(), NETTYPE); |
105 | if(pJob->Result() == 0) |
106 | { |
107 | EXPECT_EQ(pJob->Addr().type & NETTYPE, pJob->Addr().type); |
108 | } |
109 | } |
110 | |
111 | TEST_F(Jobs, LookupHostWebsocket) |
112 | { |
113 | static const char *HOST = "ws://example.com" ; |
114 | static const int NETTYPE = NETTYPE_ALL; |
115 | auto pJob = std::make_shared<CHostLookup>(args&: HOST, args: NETTYPE); |
116 | |
117 | EXPECT_STREQ(pJob->Hostname(), HOST); |
118 | EXPECT_EQ(pJob->Nettype(), NETTYPE); |
119 | |
120 | Add(pJob); |
121 | while(pJob->State() != IJob::STATE_DONE) |
122 | { |
123 | // yay, busy loop... |
124 | thread_yield(); |
125 | } |
126 | |
127 | EXPECT_STREQ(pJob->Hostname(), HOST); |
128 | EXPECT_EQ(pJob->Nettype(), NETTYPE); |
129 | if(pJob->Result() == 0) |
130 | { |
131 | EXPECT_EQ(pJob->Addr().type & NETTYPE_WEBSOCKET_IPV4, pJob->Addr().type); |
132 | } |
133 | } |
134 | |
135 | TEST_F(Jobs, Many) |
136 | { |
137 | std::atomic<int> ThreadsRunning(0); |
138 | std::vector<std::shared_ptr<IJob>> vpJobs; |
139 | SEMAPHORE sphore; |
140 | sphore_init(sem: &sphore); |
141 | for(int i = 0; i < TEST_NUM_THREADS; i++) |
142 | { |
143 | std::shared_ptr<IJob> pJob = std::make_shared<CJob>(args: [&] { |
144 | int Prev = ThreadsRunning.fetch_add(i: 1); |
145 | if(Prev == TEST_NUM_THREADS - 1) |
146 | { |
147 | sphore_signal(sem: &sphore); |
148 | } |
149 | }); |
150 | EXPECT_EQ(pJob->State(), IJob::STATE_QUEUED); |
151 | vpJobs.push_back(x: pJob); |
152 | } |
153 | for(auto &pJob : vpJobs) |
154 | { |
155 | Add(pJob); |
156 | } |
157 | sphore_wait(sem: &sphore); |
158 | sphore_destroy(sem: &sphore); |
159 | TearDown(); |
160 | for(auto &pJob : vpJobs) |
161 | { |
162 | EXPECT_EQ(pJob->State(), IJob::STATE_DONE); |
163 | } |
164 | SetUp(); |
165 | } |
166 | |