Change char unique_ptr to char vector
[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     close(fd[0]);
51     close(fd[1]);
52 }
53
54 /*
55  * Declares pipe descriptor array
56  * Creates pipe and checks for error
57  * Wraps pipe in unique_ptr
58  */
59 #define PIPE(fd) \
60     int (fd)[2]; \
61     BOOST_REQUIRE_MESSAGE(0 == pipe((fd)),"Pipe creation failed: " << GetErrnoString()); \
62     PipePtr fd##Ptr((fd), closePipe);
63
64 void unexpectedCallback(int, short) {
65     BOOST_FAIL("Unexpected callback");
66 }
67
68 void readFd(int fd, int expectedFd, short revents) {
69     char buf[1];
70     BOOST_REQUIRE_MESSAGE(fd == expectedFd, "Unexpected descriptor");
71     BOOST_REQUIRE_MESSAGE(revents & POLLIN, "Unexpected event");
72     BOOST_REQUIRE_MESSAGE(1 == TEMP_FAILURE_RETRY(read(fd,buf,1)),
73                           "Pipe read failed" << GetErrnoString());
74 }
75
76 void writeFd(int fd, int expectedFd, short revents) {
77     BOOST_REQUIRE_MESSAGE(fd == expectedFd, "Unexpected descriptor");
78     BOOST_REQUIRE_MESSAGE(revents & POLLOUT, "Unexpected event");
79     BOOST_REQUIRE_MESSAGE(1 == TEMP_FAILURE_RETRY(write(fd,"j",1)),
80                           "Pipe writing failed" << GetErrnoString());
81 }
82
83 } // anonymous namespace
84
85 BOOST_AUTO_TEST_SUITE(DESCRIPTOR_SET_TEST)
86
87 /*
88  * Wait on empty descriptor set. Function should return immediately.
89  */
90 BOOST_AUTO_TEST_CASE(T010_Empty) {
91     DescriptorSet descriptors;
92
93     BOOST_REQUIRE_NO_THROW(descriptors.wait(POLL_TIMEOUT));
94 }
95
96 /*
97  * Add and remove (twice) descriptor. Wait on empty set. No callback should be called. wait() should
98  * return immediately.
99  */
100 BOOST_AUTO_TEST_CASE(T020_AddRemove) {
101     DescriptorSet descriptors;
102     descriptors.add(10, POLLALL, unexpectedCallback);
103     descriptors.remove(10);
104     descriptors.remove(10);
105
106     BOOST_REQUIRE_NO_THROW(descriptors.wait(POLL_TIMEOUT));
107 }
108
109 /*
110  * Add 2 descriptors and purge all. Wait on empty set. No callback should be called. wait() should
111  * return immediately.
112  */
113 BOOST_AUTO_TEST_CASE(T030_AddPurge) {
114     DescriptorSet descriptors;
115     descriptors.add(10, POLLALL, unexpectedCallback);
116     descriptors.add(20, POLLALL, unexpectedCallback);
117     descriptors.purge();
118
119     BOOST_REQUIRE_NO_THROW(descriptors.wait(POLL_TIMEOUT));
120 }
121
122 /*
123  * Add pipe[1] descriptor and wait for write possibility. Provided callback should be called
124  * immediately.
125  */
126 BOOST_AUTO_TEST_CASE(T040_Callback) {
127     DescriptorSet descriptors;
128     bool callback = false;
129
130     PIPE(fd);
131
132     descriptors.add(fd[1],POLLALL, [&callback](int, short revents)
133     {
134         callback = true;
135         BOOST_REQUIRE_MESSAGE(revents & POLLOUT, "Not able to write");
136     });
137
138     BOOST_REQUIRE_NO_THROW(descriptors.wait(POLL_TIMEOUT));
139     BOOST_REQUIRE_MESSAGE(callback, "Callback was not called");
140 }
141
142 /*
143  * Add pipe[1] descriptor twice with different callbacks. The first one should be overwritten and
144  * shouldn't be called. The second one should be called instead.
145  */
146 BOOST_AUTO_TEST_CASE(T050_DoubleAdd) {
147     DescriptorSet descriptors;
148     bool callback = false;
149
150     PIPE(fd);
151
152     descriptors.add(fd[1], POLLALL, unexpectedCallback);
153     descriptors.add(fd[1], POLLALL, [&callback](int, short revents)
154     {
155         callback = true;
156         BOOST_REQUIRE_MESSAGE(revents & POLLOUT, "Not able to write");
157     });
158
159     BOOST_REQUIRE_NO_THROW(descriptors.wait(POLL_TIMEOUT));
160     BOOST_REQUIRE_MESSAGE(callback, "Callback was not called");
161 }
162
163 /*
164  * Add pipe[0] descriptor and wait. Callback should not be called. Instead the 8s timeout should
165  * occur and a proper exception should be thrown.
166  */
167 BOOST_AUTO_TEST_CASE(T060_Timeout) {
168     DescriptorSet descriptors;
169
170     PIPE(fd);
171
172     descriptors.add(fd[0],POLLALL, unexpectedCallback);
173
174     BOOST_REQUIRE_THROW(descriptors.wait(POLL_TIMEOUT_SHORT), CKM::DescriptorSet::Timeout);
175 }
176
177 /*
178  * Create pipe and try to write it. Start thread that will read it.
179  */
180 BOOST_AUTO_TEST_CASE(T070_Write) {
181     DescriptorSet descriptors;
182     bool callback = false;
183
184     PIPE(fd);
185
186     descriptors.add(fd[1],POLLOUT, [&fd, &callback](int desc, short revents)
187     {
188         callback = true;
189         writeFd(desc, fd[1], revents);
190     } );
191
192     {
193         auto thread = CreateWatchedThread([fd]
194         {
195             char buf[1];
196             ssize_t tmp = TEMP_FAILURE_RETRY(read(fd[0], buf, 1));
197             THREAD_REQUIRE_MESSAGE(tmp == 1, "Pipe reading failed " << GetErrnoString());
198         });
199
200         BOOST_REQUIRE_NO_THROW(descriptors.wait(POLL_TIMEOUT));
201     }
202
203     BOOST_REQUIRE_MESSAGE(callback, "Callback not called");
204 }
205
206 /*
207  * Create pipe and try to read it. Start thread that will write it.
208  */
209 BOOST_AUTO_TEST_CASE(T080_Read) {
210     DescriptorSet descriptors;
211     bool callback = false;
212
213     PIPE(fd);
214
215     descriptors.add(fd[0],POLLIN, [&](int desc, short revents)
216     {
217         callback = true;
218         readFd(desc, fd[0], revents);
219     } );
220
221     {
222         auto thread = CreateWatchedThread([fd]
223         {
224             ssize_t tmp = TEMP_FAILURE_RETRY(write(fd[1], "j", 1));
225             THREAD_REQUIRE_MESSAGE(tmp == 1, "Pipe writing failed " << GetErrnoString());
226         });
227
228         BOOST_REQUIRE_NO_THROW(descriptors.wait(POLL_TIMEOUT));
229     }
230
231     BOOST_REQUIRE_MESSAGE(callback, "Callback not called");
232 }
233
234 /*
235  * Create two pipes. Try to read first one. Start the thread that writes it. In the callback read
236  * the pipe, remove it from the descriptor set and try to write the second pipe. The thread will
237  * read it. In second pipe callback remove the second pipe descriptor from the set.
238  */
239 BOOST_AUTO_TEST_CASE(T090_WriteAfterRead) {
240     DescriptorSet descriptors;
241     bool callback1 = false;
242     bool callback2 = false;
243
244     PIPE(fd);
245     PIPE(fd2);
246
247     descriptors.add(fd[0],POLLIN, [&](int desc, short revents)
248     {
249         callback1 = true;
250         readFd(desc, fd[0], revents);
251
252         descriptors.remove(desc);
253         descriptors.add(fd2[1],POLLOUT, [&](int desc, short revents) {
254             callback2 = true;
255             writeFd(desc, fd2[1], revents);
256             descriptors.remove(desc);
257         } );
258     } );
259
260     {
261         auto thread = CreateWatchedThread([fd,fd2]
262         {
263             ssize_t tmp = TEMP_FAILURE_RETRY(write(fd[1], "j", 1));
264             BOOST_REQUIRE_MESSAGE(tmp == 1, "Pipe writing failed " << GetErrnoString());
265
266             char buf[1];
267             tmp = TEMP_FAILURE_RETRY(read(fd2[0], buf, 1));
268             THREAD_REQUIRE_MESSAGE(tmp == 1, "Pipe reading failed " << GetErrnoString());
269         });
270
271         BOOST_REQUIRE_NO_THROW(descriptors.wait(POLL_TIMEOUT));
272         BOOST_REQUIRE_NO_THROW(descriptors.wait(POLL_TIMEOUT));
273     }
274
275     BOOST_REQUIRE_MESSAGE(callback1, "First callback not called");
276     BOOST_REQUIRE_MESSAGE(callback2, "Second callback not called");
277 }
278
279 BOOST_AUTO_TEST_SUITE_END()