Fix build break with boost 1.71.0
[platform/core/security/key-manager.git] / tests / test_descriptor-set.cpp
1 /*
2  *  Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Licensed under the Apache License, Version 2.0 (the "License");
5  *  you may not use this file except in compliance with the License.
6  *  You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License
15  */
16 /*
17  * @file       test_descriptor-set.cpp
18  * @author     Krzysztof Jackiewicz (k.jackiewicz@samsung.com)
19  * @version    1.0
20  */
21
22 #include <unistd.h>
23 #include <errno.h>
24 #include <string.h>
25
26 #include <thread>
27 #include <memory>
28
29 #include <boost/test/unit_test.hpp>
30 #include <boost/test/results_reporter.hpp>
31
32 #include <test_common.h>
33 #include <test_watched-thread.h>
34
35 #include <descriptor-set.h>
36 #include <dpl/errno_string.h>
37
38 using namespace CKM;
39
40 namespace {
41
42 const int POLL_TIMEOUT = 8000;
43 const int POLL_TIMEOUT_SHORT = 1000;
44
45 typedef std::unique_ptr<int[], std::function<void(int *)>> PipePtr;
46
47 const short POLLALL = std::numeric_limits<short>::max();
48
49 void closePipe(int *fd)
50 {
51         close(fd[0]);
52         close(fd[1]);
53 }
54
55 /*
56  * Declares pipe descriptor array
57  * Creates pipe and checks for error
58  * Wraps pipe in unique_ptr
59  */
60 #define PIPE(fd) \
61         int (fd)[2]; \
62         BOOST_REQUIRE_MESSAGE(0 == pipe((fd)), "Pipe creation failed: " << GetErrnoString()); \
63         PipePtr fd##Ptr((fd), closePipe);
64
65 void unexpectedCallback(int, short)
66 {
67         BOOST_FAIL("Unexpected callback");
68 }
69
70 void readFd(int fd, int expectedFd, short revents)
71 {
72         char buf[1];
73         BOOST_REQUIRE_MESSAGE(fd == expectedFd, "Unexpected descriptor");
74         BOOST_REQUIRE_MESSAGE(revents & POLLIN, "Unexpected event");
75         BOOST_REQUIRE_MESSAGE(1 == TEMP_FAILURE_RETRY(read(fd, buf, 1)),
76                                                   "Pipe read failed" << GetErrnoString());
77 }
78
79 void writeFd(int fd, int expectedFd, short revents)
80 {
81         BOOST_REQUIRE_MESSAGE(fd == expectedFd, "Unexpected descriptor");
82         BOOST_REQUIRE_MESSAGE(revents & POLLOUT, "Unexpected event");
83         BOOST_REQUIRE_MESSAGE(1 == TEMP_FAILURE_RETRY(write(fd, "j", 1)),
84                                                   "Pipe writing failed" << GetErrnoString());
85 }
86
87 } // anonymous namespace
88
89 BOOST_AUTO_TEST_SUITE(DESCRIPTOR_SET_TEST)
90
91 /*
92  * Wait on empty descriptor set. Function should return immediately.
93  */
94 BOOST_AUTO_TEST_CASE(T010_Empty)
95 {
96         DescriptorSet descriptors;
97
98         BOOST_REQUIRE_NO_THROW(descriptors.wait(POLL_TIMEOUT));
99 }
100
101 /*
102  * Add and remove (twice) descriptor. Wait on empty set. No callback should be called. wait() should
103  * return immediately.
104  */
105 BOOST_AUTO_TEST_CASE(T020_AddRemove)
106 {
107         DescriptorSet descriptors;
108         descriptors.add(10, POLLALL, unexpectedCallback);
109         descriptors.remove(10);
110         descriptors.remove(10);
111
112         BOOST_REQUIRE_NO_THROW(descriptors.wait(POLL_TIMEOUT));
113 }
114
115 /*
116  * Add 2 descriptors and purge all. Wait on empty set. No callback should be called. wait() should
117  * return immediately.
118  */
119 BOOST_AUTO_TEST_CASE(T030_AddPurge)
120 {
121         DescriptorSet descriptors;
122         descriptors.add(10, POLLALL, unexpectedCallback);
123         descriptors.add(20, POLLALL, unexpectedCallback);
124         descriptors.purge();
125
126         BOOST_REQUIRE_NO_THROW(descriptors.wait(POLL_TIMEOUT));
127 }
128
129 /*
130  * Add pipe[1] descriptor and wait for write possibility. Provided callback should be called
131  * immediately.
132  */
133 BOOST_AUTO_TEST_CASE(T040_Callback)
134 {
135         DescriptorSet descriptors;
136         bool callback = false;
137
138         PIPE(fd);
139
140         descriptors.add(fd[1], POLLALL, [&callback](int, short revents) {
141                 callback = true;
142                 BOOST_REQUIRE_MESSAGE(revents & POLLOUT, "Not able to write");
143         });
144
145         BOOST_REQUIRE_NO_THROW(descriptors.wait(POLL_TIMEOUT));
146         BOOST_REQUIRE_MESSAGE(callback, "Callback was not called");
147 }
148
149 /*
150  * Add pipe[1] descriptor twice with different callbacks. The first one should be overwritten and
151  * shouldn't be called. The second one should be called instead.
152  */
153 BOOST_AUTO_TEST_CASE(T050_DoubleAdd)
154 {
155         DescriptorSet descriptors;
156         bool callback = false;
157
158         PIPE(fd);
159
160         descriptors.add(fd[1], POLLALL, unexpectedCallback);
161         descriptors.add(fd[1], POLLALL, [&callback](int, short revents) {
162                 callback = true;
163                 BOOST_REQUIRE_MESSAGE(revents & POLLOUT, "Not able to write");
164         });
165
166         BOOST_REQUIRE_NO_THROW(descriptors.wait(POLL_TIMEOUT));
167         BOOST_REQUIRE_MESSAGE(callback, "Callback was not called");
168 }
169
170 /*
171  * Add pipe[0] descriptor and wait. Callback should not be called. Instead the 8s timeout should
172  * occur and a proper exception should be thrown.
173  */
174 BOOST_AUTO_TEST_CASE(T060_Timeout)
175 {
176         DescriptorSet descriptors;
177
178         PIPE(fd);
179
180         descriptors.add(fd[0], POLLALL, unexpectedCallback);
181
182         BOOST_REQUIRE_THROW(descriptors.wait(POLL_TIMEOUT_SHORT),
183                                                 CKM::DescriptorSet::Timeout);
184 }
185
186 /*
187  * Create pipe and try to write it. Start thread that will read it.
188  */
189 BOOST_AUTO_TEST_CASE(T070_Write)
190 {
191         DescriptorSet descriptors;
192         bool callback = false;
193
194         PIPE(fd);
195
196         descriptors.add(fd[1], POLLOUT, [&fd, &callback](int desc, short revents) {
197                 callback = true;
198                 writeFd(desc, fd[1], revents);
199         });
200
201         {
202                 auto thread = CreateWatchedThread([fd] {
203                         char buf[1];
204                         ssize_t tmp = TEMP_FAILURE_RETRY(read(fd[0], buf, 1));
205                         THREAD_REQUIRE_MESSAGE(tmp == 1, "Pipe reading failed " << GetErrnoString());
206                 });
207
208                 BOOST_REQUIRE_NO_THROW(descriptors.wait(POLL_TIMEOUT));
209         }
210
211         BOOST_REQUIRE_MESSAGE(callback, "Callback not called");
212 }
213
214 /*
215  * Create pipe and try to read it. Start thread that will write it.
216  */
217 BOOST_AUTO_TEST_CASE(T080_Read)
218 {
219         DescriptorSet descriptors;
220         bool callback = false;
221
222         PIPE(fd);
223
224         descriptors.add(fd[0], POLLIN, [&](int desc, short revents) {
225                 callback = true;
226                 readFd(desc, fd[0], revents);
227         });
228
229         {
230                 auto thread = CreateWatchedThread([fd] {
231                         ssize_t tmp = TEMP_FAILURE_RETRY(write(fd[1], "j", 1));
232                         THREAD_REQUIRE_MESSAGE(tmp == 1, "Pipe writing failed " << GetErrnoString());
233                 });
234
235                 BOOST_REQUIRE_NO_THROW(descriptors.wait(POLL_TIMEOUT));
236         }
237
238         BOOST_REQUIRE_MESSAGE(callback, "Callback not called");
239 }
240
241 /*
242  * Create two pipes. Try to read first one. Start the thread that writes it. In the callback read
243  * the pipe, remove it from the descriptor set and try to write the second pipe. The thread will
244  * read it. In second pipe callback remove the second pipe descriptor from the set.
245  */
246 BOOST_AUTO_TEST_CASE(T090_WriteAfterRead)
247 {
248         DescriptorSet descriptors;
249         bool callback1 = false;
250         bool callback2 = false;
251
252         PIPE(fd);
253         PIPE(fd2);
254
255         descriptors.add(fd[0], POLLIN, [&](int desc, short revents) {
256                 callback1 = true;
257                 readFd(desc, fd[0], revents);
258
259                 descriptors.remove(desc);
260                 descriptors.add(fd2[1], POLLOUT, [&](int desc, short revents) {
261                         callback2 = true;
262                         writeFd(desc, fd2[1], revents);
263                         descriptors.remove(desc);
264                 });
265         });
266
267         {
268                 auto thread = CreateWatchedThread([fd, fd2] {
269                         ssize_t tmp = TEMP_FAILURE_RETRY(write(fd[1], "j", 1));
270                         BOOST_REQUIRE_MESSAGE(tmp == 1, "Pipe writing failed " << GetErrnoString());
271
272                         char buf[1];
273                         tmp = TEMP_FAILURE_RETRY(read(fd2[0], buf, 1));
274                         THREAD_REQUIRE_MESSAGE(tmp == 1, "Pipe reading failed " << GetErrnoString());
275                 });
276
277                 BOOST_REQUIRE_NO_THROW(descriptors.wait(POLL_TIMEOUT));
278                 BOOST_REQUIRE_NO_THROW(descriptors.wait(POLL_TIMEOUT));
279         }
280
281         BOOST_REQUIRE_MESSAGE(callback1, "First callback not called");
282         BOOST_REQUIRE_MESSAGE(callback2, "Second callback not called");
283 }
284
285 BOOST_AUTO_TEST_SUITE_END()