1 // Copyright (C) 2013-2020 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7 #include <config.h>
8
9 #include <hooks/callout_handle.h>
10 #include <hooks/callout_manager.h>
11 #include <hooks/library_handle.h>
12 #include <hooks/server_hooks.h>
13
14 #include <boost/shared_ptr.hpp>
15
16 #include <gtest/gtest.h>
17
18 using namespace isc::hooks;
19 using namespace std;
20
21 namespace {
22
23 /// @file
24 /// @brief Holds the CalloutHandle argument tests
25 ///
26 /// Additional testing of the CalloutHandle - together with the interaction
27 /// of the LibraryHandle - is done in the handles_unittests set of tests.
28
29 class CalloutHandleTest : public ::testing::Test {
30 public:
31
32 /// @brief Constructor
33 ///
34 /// Sets up a callout manager to be referenced by the CalloutHandle in
35 /// these tests. (The "4" for the number of libraries in the
36 /// CalloutManager is arbitrary - it is not used in these tests.)
CalloutHandleTest()37 CalloutHandleTest() : manager_(new CalloutManager(4))
38 {}
39
40 /// Obtain hook manager
getCalloutManager()41 boost::shared_ptr<CalloutManager>& getCalloutManager() {
42 return (manager_);
43 }
44
45 private:
46 /// Callout manager accessed by this CalloutHandle.
47 boost::shared_ptr<CalloutManager> manager_;
48 };
49
50 // *** Argument Tests ***
51 //
52 // The first set of tests check that the CalloutHandle can store and retrieve
53 // arguments. These are very similar to the LibraryHandle context tests.
54
55 // Test that we can store multiple values of the same type and that they
56 // are distinct.
57
TEST_F(CalloutHandleTest,ArgumentDistinctSimpleType)58 TEST_F(CalloutHandleTest, ArgumentDistinctSimpleType) {
59 CalloutHandle handle(getCalloutManager());
60
61 // Store and retrieve an int (random value).
62 int a = 42;
63 handle.setArgument("integer1", a);
64 EXPECT_EQ(42, a);
65
66 int b = 0;
67 handle.getArgument("integer1", b);
68 EXPECT_EQ(42, b);
69
70 // Add another integer (another random value).
71 int c = 142;
72 handle.setArgument("integer2", c);
73 EXPECT_EQ(142, c);
74
75 int d = 0;
76 handle.getArgument("integer2", d);
77 EXPECT_EQ(142, d);
78
79 // Add a short (random value).
80 short e = -81;
81 handle.setArgument("short", e);
82 EXPECT_EQ(-81, e);
83
84 short f = 0;
85 handle.getArgument("short", f);
86 EXPECT_EQ(-81, f);
87 }
88
89 // Test that trying to get an unknown argument throws an exception.
90
TEST_F(CalloutHandleTest,ArgumentUnknownName)91 TEST_F(CalloutHandleTest, ArgumentUnknownName) {
92 CalloutHandle handle(getCalloutManager());
93
94 // Set an integer
95 int a = 42;
96 handle.setArgument("integer1", a);
97 EXPECT_EQ(42, a);
98
99 // Check we can retrieve it
100 int b = 0;
101 handle.getArgument("integer1", b);
102 EXPECT_EQ(42, b);
103
104 // Check that getting an unknown name throws an exception.
105 int c = 0;
106 EXPECT_THROW(handle.getArgument("unknown", c), NoSuchArgument);
107 }
108
109 // Test that trying to get an argument with an incorrect type throws an
110 // exception.
111
TEST_F(CalloutHandleTest,ArgumentIncorrectType)112 TEST_F(CalloutHandleTest, ArgumentIncorrectType) {
113 CalloutHandle handle(getCalloutManager());
114
115 // Set an integer
116 int a = 42;
117 handle.setArgument("integer1", a);
118 EXPECT_EQ(42, a);
119
120 // Check we can retrieve it
121 long b = 0;
122 EXPECT_THROW(handle.getArgument("integer1", b), boost::bad_any_cast);
123 }
124
125 // Now try with some very complex types. The types cannot be defined within
126 // the function and they should contain a copy constructor. For this reason,
127 // a simple "struct" is used.
128
129 struct Alpha {
130 int a;
131 int b;
Alpha__anon679132800111::Alpha132 Alpha(int first = 0, int second = 0) : a(first), b(second) {}
133 };
134
135 struct Beta {
136 int c;
137 int d;
Beta__anon679132800111::Beta138 Beta(int first = 0, int second = 0) : c(first), d(second) {}
139 };
140
TEST_F(CalloutHandleTest,ComplexTypes)141 TEST_F(CalloutHandleTest, ComplexTypes) {
142 CalloutHandle handle(getCalloutManager());
143
144 // Declare two variables of different (complex) types. (Note as to the
145 // variable names: aleph and beth are the first two letters of the Hebrew
146 // alphabet.)
147 Alpha aleph(1, 2);
148 EXPECT_EQ(1, aleph.a);
149 EXPECT_EQ(2, aleph.b);
150 handle.setArgument("aleph", aleph);
151
152 Beta beth(11, 22);
153 EXPECT_EQ(11, beth.c);
154 EXPECT_EQ(22, beth.d);
155 handle.setArgument("beth", beth);
156
157 // Ensure we can extract the data correctly.
158 Alpha aleph2;
159 EXPECT_EQ(0, aleph2.a);
160 EXPECT_EQ(0, aleph2.b);
161 handle.getArgument("aleph", aleph2);
162 EXPECT_EQ(1, aleph2.a);
163 EXPECT_EQ(2, aleph2.b);
164
165 Beta beth2;
166 EXPECT_EQ(0, beth2.c);
167 EXPECT_EQ(0, beth2.d);
168 handle.getArgument("beth", beth2);
169 EXPECT_EQ(11, beth2.c);
170 EXPECT_EQ(22, beth2.d);
171
172 // Ensure that complex types also thrown an exception if we attempt to
173 // get a context element of the wrong type.
174 EXPECT_THROW(handle.getArgument("aleph", beth), boost::bad_any_cast);
175 }
176
177 // Check that the context can store pointers. And also check that it respects
178 // that a "pointer to X" is not the same as a "pointer to const X".
179
TEST_F(CalloutHandleTest,PointerTypes)180 TEST_F(CalloutHandleTest, PointerTypes) {
181 CalloutHandle handle(getCalloutManager());
182
183 // Declare a couple of variables, const and non-const.
184 Alpha aleph(5, 10);
185 const Beta beth(15, 20);
186
187 Alpha* pa = ℵ
188 const Beta* pcb = ℶ
189
190 // Check pointers can be set and retrieved OK.
191 handle.setArgument("non_const_pointer", pa);
192 handle.setArgument("const_pointer", pcb);
193
194 Alpha* pa2 = 0;
195 handle.getArgument("non_const_pointer", pa2);
196 EXPECT_TRUE(pa == pa2);
197
198 const Beta* pcb2 = 0;
199 handle.getArgument("const_pointer", pcb2);
200 EXPECT_TRUE(pcb == pcb2);
201
202 // Check that the "const" is protected in the context.
203 const Alpha* pca3;
204 EXPECT_THROW(handle.getArgument("non_const_pointer", pca3),
205 boost::bad_any_cast);
206
207 Beta* pb3;
208 EXPECT_THROW(handle.getArgument("const_pointer", pb3),
209 boost::bad_any_cast);
210 }
211
212 // Check that we can get the names of the arguments.
213
TEST_F(CalloutHandleTest,ContextItemNames)214 TEST_F(CalloutHandleTest, ContextItemNames) {
215 CalloutHandle handle(getCalloutManager());
216
217 vector<string> expected_names;
218
219 expected_names.push_back("faith");
220 handle.setArgument("faith", 42);
221 expected_names.push_back("hope");
222 handle.setArgument("hope", 43);
223 expected_names.push_back("charity");
224 handle.setArgument("charity", 44);
225
226 // Get the names and check against the expected names. We'll sort
227 // both arrays to simplify the checking.
228 vector<string> actual_names = handle.getArgumentNames();
229
230 sort(actual_names.begin(), actual_names.end());
231 sort(expected_names.begin(), expected_names.end());
232 EXPECT_TRUE(expected_names == actual_names);
233 }
234
235 // Test that we can delete an argument.
236
TEST_F(CalloutHandleTest,DeleteArgument)237 TEST_F(CalloutHandleTest, DeleteArgument) {
238 CalloutHandle handle(getCalloutManager());
239
240 int one = 1;
241 int two = 2;
242 int three = 3;
243 int four = 4;
244 int value; // Return value
245
246 handle.setArgument("one", one);
247 handle.setArgument("two", two);
248 handle.setArgument("three", three);
249 handle.setArgument("four", four);
250
251 // Delete "one".
252 handle.getArgument("one", value);
253 EXPECT_EQ(1, value);
254 handle.deleteArgument("one");
255
256 EXPECT_THROW(handle.getArgument("one", value), NoSuchArgument);
257 handle.getArgument("two", value);
258 EXPECT_EQ(2, value);
259 handle.getArgument("three", value);
260 EXPECT_EQ(3, value);
261 handle.getArgument("four", value);
262 EXPECT_EQ(4, value);
263
264 // Delete "three".
265 handle.getArgument("three", value);
266 EXPECT_EQ(3, value);
267 handle.deleteArgument("three");
268
269 EXPECT_THROW(handle.getArgument("one", value), NoSuchArgument);
270 handle.getArgument("two", value);
271 EXPECT_EQ(2, value);
272 EXPECT_THROW(handle.getArgument("three", value), NoSuchArgument);
273 handle.getArgument("four", value);
274 EXPECT_EQ(4, value);
275 }
276
277 // Test that we can delete all arguments.
278
TEST_F(CalloutHandleTest,DeleteAllArguments)279 TEST_F(CalloutHandleTest, DeleteAllArguments) {
280 CalloutHandle handle(getCalloutManager());
281
282 int one = 1;
283 int two = 2;
284 int three = 3;
285 int four = 4;
286 int value; // Return value
287
288 // Set the arguments. The previous test verifies that this works.
289 handle.setArgument("one", one);
290 handle.setArgument("two", two);
291 handle.setArgument("three", three);
292 handle.setArgument("four", four);
293
294 // Delete all arguments...
295 handle.deleteAllArguments();
296
297 // ... and check that none are left.
298 EXPECT_THROW(handle.getArgument("one", value), NoSuchArgument);
299 EXPECT_THROW(handle.getArgument("two", value), NoSuchArgument);
300 EXPECT_THROW(handle.getArgument("three", value), NoSuchArgument);
301 EXPECT_THROW(handle.getArgument("four", value), NoSuchArgument);
302 }
303
304 // Test the "status" field.
TEST_F(CalloutHandleTest,StatusField)305 TEST_F(CalloutHandleTest, StatusField) {
306 CalloutHandle handle(getCalloutManager());
307
308 // Should be continue on construction.
309 EXPECT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, handle.getStatus());
310
311 handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
312 EXPECT_EQ(CalloutHandle::NEXT_STEP_SKIP, handle.getStatus());
313
314 handle.setStatus(CalloutHandle::NEXT_STEP_DROP);
315 EXPECT_EQ(CalloutHandle::NEXT_STEP_DROP, handle.getStatus());
316
317 handle.setStatus(CalloutHandle::NEXT_STEP_CONTINUE);
318 EXPECT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, handle.getStatus());
319 }
320
321 // Tests that ScopedCalloutHandleState object resets CalloutHandle state
322 // during construction and destruction.
TEST_F(CalloutHandleTest,scopedState)323 TEST_F(CalloutHandleTest, scopedState) {
324 // Create pointer to the handle to be wrapped.
325 CalloutHandlePtr handle(new CalloutHandle(getCalloutManager()));
326
327 // Set two arguments and the non-default status.
328 int one = 1;
329 int two = 2;
330 int three = 3;
331 handle->setArgument("one", one);
332 handle->setArgument("two", two);
333 handle->setContext("three", three);
334 handle->setStatus(CalloutHandle::NEXT_STEP_DROP);
335
336
337 int value = 0;
338 EXPECT_NO_THROW(handle->getArgument("one", value));
339 EXPECT_NO_THROW(handle->getArgument("two", value));
340 EXPECT_NO_THROW(handle->getContext("three", value));
341 EXPECT_EQ(CalloutHandle::NEXT_STEP_DROP, handle->getStatus());
342
343 {
344 // Wrap the callout handle with the scoped state object, which should
345 // reset the state of the handle.
346 ScopedCalloutHandleState scoped_state(handle);
347
348 // When state is reset, all arguments should be removed and the
349 // default status should be set.
350 EXPECT_THROW(handle->getArgument("one", value), NoSuchArgument);
351 EXPECT_THROW(handle->getArgument("two", value), NoSuchArgument);
352 EXPECT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, handle->getStatus());
353
354 // Context should be intact.
355 ASSERT_NO_THROW(handle->getContext("three", value));
356 EXPECT_EQ(three, value);
357
358 // Set the arguments and status again prior to the destruction of
359 // the wrapper.
360 handle->setArgument("one", one);
361 handle->setArgument("two", two);
362 handle->setStatus(CalloutHandle::NEXT_STEP_DROP);
363
364 EXPECT_NO_THROW(handle->getArgument("one", value));
365 EXPECT_NO_THROW(handle->getArgument("two", value));
366 EXPECT_EQ(CalloutHandle::NEXT_STEP_DROP, handle->getStatus());
367 }
368
369 // Arguments should be gone again and the status should be set to
370 // a default value.
371 EXPECT_THROW(handle->getArgument("one", value), NoSuchArgument);
372 EXPECT_THROW(handle->getArgument("two", value), NoSuchArgument);
373 EXPECT_EQ(CalloutHandle::NEXT_STEP_CONTINUE, handle->getStatus());
374
375 // Context should be intact.
376 ASSERT_NO_THROW(handle->getContext("three", value));
377 EXPECT_EQ(three, value);
378 }
379
380 // Further tests of the "skip" flag and tests of getting the name of the
381 // hook to which the current callout is attached is in the "handles_unittest"
382 // module.
383
384 } // Anonymous namespace
385