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 = &aleph;
188     const Beta* pcb = &beth;
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