2 * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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
17 * @file test_descriptor-set.cpp
18 * @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com)
25 #include <sys/types.h>
26 #include <sys/resource.h>
34 #include <boost_macros_wrapper.h>
35 #include <boost/test/results_reporter.hpp>
37 #include <test_common.h>
38 #include <test_watched-thread.h>
40 #include <descriptor-set.h>
41 #include <dpl/errno_string.h>
48 const int POLL_TIMEOUT = 8000;
49 const int POLL_TIMEOUT_SHORT = 1000;
51 const short POLLALL = std::numeric_limits<short>::max();
53 void closePipe(int *fd)
60 * Declares pipe descriptor array
61 * Creates pipe and checks for error
62 * Wraps pipe in unique_ptr
66 BOOST_REQUIRE_MESSAGE(0 == pipe((fd)), "Pipe creation failed: " << GetErrnoString()); \
67 auto fd##Ptr = uptr<closePipe>((fd));
69 void unexpectedCallback(int, short)
71 BOOST_FAIL("Unexpected callback");
74 void readFd(int fd, int expectedFd, short revents)
77 BOOST_REQUIRE_MESSAGE(fd == expectedFd, "Unexpected descriptor");
78 BOOST_REQUIRE_MESSAGE(revents & POLLIN, "Unexpected event");
79 BOOST_REQUIRE_MESSAGE(1 == TEMP_FAILURE_RETRY(read(fd, buf, 1)),
80 "Pipe read failed" << GetErrnoString());
83 void writeFd(int fd, int expectedFd, short revents)
85 BOOST_REQUIRE_MESSAGE(fd == expectedFd, "Unexpected descriptor");
86 BOOST_REQUIRE_MESSAGE(revents & POLLOUT, "Unexpected event");
87 BOOST_REQUIRE_MESSAGE(1 == TEMP_FAILURE_RETRY(write(fd, "j", 1)),
88 "Pipe writing failed" << GetErrnoString());
91 } // anonymous namespace
93 BOOST_AUTO_TEST_SUITE(DESCRIPTOR_SET_TEST)
96 * Wait on empty descriptor set. Function should return immediately.
98 POSITIVE_TEST_CASE(T010_Empty)
100 DescriptorSet descriptors;
102 BOOST_REQUIRE_NO_THROW(descriptors.wait(POLL_TIMEOUT));
106 * Add and remove (twice) descriptor. Wait on empty set. No callback should be called. wait() should
107 * return immediately.
109 POSITIVE_TEST_CASE(T020_AddRemove)
111 DescriptorSet descriptors;
112 descriptors.add(10, POLLALL, unexpectedCallback);
113 descriptors.remove(10);
114 descriptors.remove(10);
116 BOOST_REQUIRE_NO_THROW(descriptors.wait(POLL_TIMEOUT));
120 * Add 2 descriptors and purge all. Wait on empty set. No callback should be called. wait() should
121 * return immediately.
123 POSITIVE_TEST_CASE(T030_AddPurge)
125 DescriptorSet descriptors;
126 descriptors.add(10, POLLALL, unexpectedCallback);
127 descriptors.add(20, POLLALL, unexpectedCallback);
130 BOOST_REQUIRE_NO_THROW(descriptors.wait(POLL_TIMEOUT));
134 * Add pipe[1] descriptor and wait for write possibility. Provided callback should be called
137 POSITIVE_TEST_CASE(T040_Callback)
139 DescriptorSet descriptors;
140 bool callback = false;
144 descriptors.add(fd[1], POLLALL, [&callback](int, short revents) {
146 BOOST_REQUIRE_MESSAGE(revents & POLLOUT, "Not able to write");
149 BOOST_REQUIRE_NO_THROW(descriptors.wait(POLL_TIMEOUT));
150 BOOST_REQUIRE_MESSAGE(callback, "Callback was not called");
154 * Add pipe[1] descriptor twice with different callbacks. The first one should be overwritten and
155 * shouldn't be called. The second one should be called instead.
157 POSITIVE_TEST_CASE(T050_DoubleAdd)
159 DescriptorSet descriptors;
160 bool callback = false;
164 descriptors.add(fd[1], POLLALL, unexpectedCallback);
165 descriptors.add(fd[1], POLLALL, [&callback](int, short revents) {
167 BOOST_REQUIRE_MESSAGE(revents & POLLOUT, "Not able to write");
170 BOOST_REQUIRE_NO_THROW(descriptors.wait(POLL_TIMEOUT));
171 BOOST_REQUIRE_MESSAGE(callback, "Callback was not called");
175 * Add pipe[0] descriptor and wait. Callback should not be called. Instead the 1s timeout should
176 * occur and a proper exception should be thrown.
178 NEGATIVE_TEST_CASE(T060_Timeout)
180 DescriptorSet descriptors;
184 descriptors.add(fd[0], POLLALL, unexpectedCallback);
186 BOOST_REQUIRE_THROW(descriptors.wait(POLL_TIMEOUT_SHORT),
187 CKM::DescriptorSet::Timeout);
191 * Create pipe and try to write it. Start thread that will read it.
193 POSITIVE_TEST_CASE(T070_Write)
195 DescriptorSet descriptors;
196 bool callback = false;
200 descriptors.add(fd[1], POLLOUT, [&fd, &callback](int desc, short revents) {
202 writeFd(desc, fd[1], revents);
206 auto thread = CreateWatchedThread([fd] {
208 ssize_t tmp = TEMP_FAILURE_RETRY(read(fd[0], buf, 1));
209 THREAD_REQUIRE_MESSAGE(tmp == 1, "Pipe reading failed " << GetErrnoString());
212 BOOST_REQUIRE_NO_THROW(descriptors.wait(POLL_TIMEOUT));
215 BOOST_REQUIRE_MESSAGE(callback, "Callback not called");
219 * Create pipe and try to read it. Start thread that will write it.
221 POSITIVE_TEST_CASE(T080_Read)
223 DescriptorSet descriptors;
224 bool callback = false;
228 descriptors.add(fd[0], POLLIN, [&](int desc, short revents) {
230 readFd(desc, fd[0], revents);
234 auto thread = CreateWatchedThread([fd] {
235 ssize_t tmp = TEMP_FAILURE_RETRY(write(fd[1], "j", 1));
236 THREAD_REQUIRE_MESSAGE(tmp == 1, "Pipe writing failed " << GetErrnoString());
239 BOOST_REQUIRE_NO_THROW(descriptors.wait(POLL_TIMEOUT));
242 BOOST_REQUIRE_MESSAGE(callback, "Callback not called");
246 * Create two pipes. Try to read first one. Start the thread that writes it. In the callback read
247 * the pipe, remove it from the descriptor set and try to write the second pipe. The thread will
248 * read it. In second pipe callback remove the second pipe descriptor from the set.
250 POSITIVE_TEST_CASE(T090_WriteAfterRead)
252 DescriptorSet descriptors;
253 bool callback1 = false;
254 bool callback2 = false;
259 descriptors.add(fd[0], POLLIN, [&](int desc, short revents) {
261 readFd(desc, fd[0], revents);
263 descriptors.remove(desc);
264 descriptors.add(fd2[1], POLLOUT, [&](int desc2, short revents) {
266 writeFd(desc2, fd2[1], revents);
267 descriptors.remove(desc2);
272 auto thread = CreateWatchedThread([fd, fd2] {
273 ssize_t tmp = TEMP_FAILURE_RETRY(write(fd[1], "j", 1));
274 BOOST_REQUIRE_MESSAGE(tmp == 1, "Pipe writing failed " << GetErrnoString());
277 tmp = TEMP_FAILURE_RETRY(read(fd2[0], buf, 1));
278 THREAD_REQUIRE_MESSAGE(tmp == 1, "Pipe reading failed " << GetErrnoString());
281 BOOST_REQUIRE_NO_THROW(descriptors.wait(POLL_TIMEOUT));
282 BOOST_REQUIRE_NO_THROW(descriptors.wait(POLL_TIMEOUT));
285 BOOST_REQUIRE_MESSAGE(callback1, "First callback not called");
286 BOOST_REQUIRE_MESSAGE(callback2, "Second callback not called");
290 * Add negative descriptor and wait. Callback should not be called. Instead the 1s timeout
291 * should occur and a proper exception should be thrown.
293 NEGATIVE_TEST_CASE(T100_AddNegativeFd)
295 DescriptorSet descriptors;
296 descriptors.add(-1, POLLALL, unexpectedCallback);
298 BOOST_REQUIRE_THROW(descriptors.wait(POLL_TIMEOUT_SHORT), DescriptorSet::Timeout);
302 * Cross the descriptor limit which should lead to EINVAL. Utilize unused descriptors only. Callback
303 * should not be called.
305 NEGATIVE_TEST_CASE(T110_DescriptorLimit)
307 DescriptorSet descriptors;
310 BOOST_REQUIRE(getrlimit(RLIMIT_NOFILE, &limit) == 0);
313 for(rlim_t i = 0; i <= limit.rlim_cur; ++fd) {
314 int ret = fcntl(fd, F_GETFD);
316 BOOST_REQUIRE(ret != -1 || err == EBADF);
318 descriptors.add(fd, POLLALL, unexpectedCallback);
323 BOOST_REQUIRE_THROW(descriptors.wait(POLL_TIMEOUT_SHORT), DescriptorSet::InternalError);
327 * Not opened descriptor should trigger a callback with error.
329 NEGATIVE_TEST_CASE(T120_NotOpenedDescriptor)
331 DescriptorSet descriptors;
333 bool callbackCalled = false;
334 auto callback = [&](int, short revents) {
335 callbackCalled = true;
336 BOOST_REQUIRE(revents == POLLNVAL);
338 descriptors.add(42, POLLALL, callback);
340 BOOST_REQUIRE_NO_THROW(descriptors.wait(POLL_TIMEOUT));
341 BOOST_REQUIRE(callbackCalled);
345 * Throwing callback. The exception should be propagated outside of DescriptorSet::wait().
347 NEGATIVE_TEST_CASE(T130_ThrowingCallback)
349 DescriptorSet descriptors;
351 auto throwingCallback = [&](int, short) {
352 throw std::runtime_error("");
354 descriptors.add(42, POLLALL, throwingCallback);
356 BOOST_REQUIRE_THROW(descriptors.wait(POLL_TIMEOUT), std::runtime_error);
360 BOOST_AUTO_TEST_SUITE_END()