Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief
5 : *
6 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
7 : */
8 :
9 : #include <kdbthread.hpp>
10 :
11 : #include <kdbprivate.h>
12 :
13 : #include <gtest/gtest.h>
14 :
15 : using namespace kdb;
16 :
17 2 : void foo1 (Coordinator & gc, KeySet & ks)
18 : {
19 4 : Key specKey ("/hello", KEY_CASCADING_NAME, KEY_END);
20 :
21 4 : ThreadContext c1 (gc);
22 6 : ThreadValue<int> v1 (ks, c1, specKey);
23 6 : ASSERT_EQ (v1, 8);
24 18 : ASSERT_EQ (ks.lookup ("user/hello").getString (), "8");
25 :
26 2 : v1 = 5;
27 6 : ASSERT_EQ (v1, 5);
28 18 : ASSERT_EQ (ks.lookup ("user/hello").getString (), "5");
29 :
30 4 : std::this_thread::sleep_for (std::chrono::milliseconds (100));
31 6 : ASSERT_EQ (v1, 5);
32 : }
33 :
34 2 : void foo2 (Coordinator & gc, KeySet & ks)
35 : {
36 4 : Key specKey ("/hello", KEY_CASCADING_NAME, KEY_END);
37 :
38 4 : ThreadContext c2 (gc);
39 6 : ThreadValue<int> v2 (ks, c2, specKey);
40 6 : ASSERT_EQ (v2, 5);
41 :
42 4 : std::this_thread::sleep_for (std::chrono::milliseconds (100));
43 2 : c2.syncLayers ();
44 6 : ASSERT_EQ (v2, 5);
45 :
46 2 : v2 = 12;
47 6 : ASSERT_EQ (v2, 12);
48 : }
49 :
50 20 : TEST (test_contextual_thread, instanciation)
51 : {
52 4 : Key specKey ("/hello", KEY_CASCADING_NAME, KEY_END);
53 :
54 4 : KeySet ks;
55 6 : ks.append (Key ("user/hello", KEY_VALUE, "22", KEY_END));
56 :
57 4 : Coordinator gc;
58 4 : ThreadContext c (gc);
59 6 : ThreadValue<int> v (ks, c, specKey);
60 6 : ASSERT_EQ (v, 22);
61 18 : ASSERT_EQ (ks.lookup ("user/hello").getString (), "22");
62 :
63 2 : v = 8;
64 6 : ASSERT_EQ (v, 8);
65 18 : ASSERT_EQ (ks.lookup ("user/hello").getString (), "8");
66 :
67 6 : std::thread t1 (foo1, std::ref (gc), std::ref (ks));
68 :
69 4 : std::this_thread::sleep_for (std::chrono::milliseconds (50));
70 18 : ASSERT_EQ (ks.lookup ("user/hello").getString (), "5");
71 2 : c.syncLayers ();
72 16 : ASSERT_TRUE (ks.lookup ("user/hello"));
73 18 : ASSERT_EQ (ks.lookup ("user/hello").getString (), "5");
74 8 : ASSERT_EQ (v.getName (), "user/hello");
75 8 : ASSERT_EQ (ks.size (), 1);
76 6 : ASSERT_EQ (v, 5);
77 :
78 6 : std::thread t2 (foo2, std::ref (gc), std::ref (ks));
79 2 : t1.join ();
80 2 : t2.join ();
81 :
82 2 : c.syncLayers ();
83 8 : ASSERT_EQ (v.getName (), "user/hello");
84 18 : ASSERT_EQ (ks.lookup ("user/hello").getString (), "12");
85 8 : ASSERT_EQ (ks.size (), 1);
86 6 : ASSERT_EQ (v, 12);
87 : }
88 :
89 12 : class Other : public kdb::Layer
90 : {
91 : public:
92 12 : std::string id () const override
93 : {
94 36 : return "other";
95 : }
96 8 : std::string operator() () const override
97 : {
98 24 : return "notused";
99 : }
100 : };
101 :
102 36 : class Activate : public kdb::Layer
103 : {
104 : public:
105 100 : std::string id () const override
106 : {
107 300 : return "activate";
108 : }
109 58 : std::string operator() () const override
110 : {
111 174 : return "active";
112 : }
113 : };
114 :
115 :
116 : bool g_toggle = false;
117 :
118 0 : void toggleOn ()
119 : {
120 2 : g_toggle = true;
121 0 : }
122 :
123 0 : void toggleOff ()
124 : {
125 2 : g_toggle = false;
126 0 : }
127 :
128 2 : void activate1 (Coordinator & gc, KeySet & ks)
129 : {
130 4 : Key specKey ("/act/%activate%", KEY_CASCADING_NAME, KEY_END);
131 :
132 4 : ThreadContext c1 (gc);
133 6 : ThreadValue<int> v1 (ks, c1, specKey);
134 6 : gc.onLayerActivation<Activate> ([]() { toggleOn (); });
135 6 : gc.onLayerDeactivation<Activate> ([]() { toggleOff (); });
136 6 : ASSERT_EQ (v1, 10);
137 4 : c1.activate<Activate> ();
138 4 : ASSERT_TRUE (g_toggle);
139 6 : ASSERT_EQ (v1, 22);
140 4 : std::this_thread::sleep_for (std::chrono::milliseconds (200));
141 6 : ASSERT_EQ (v1, 22);
142 4 : c1.deactivate<Activate> ();
143 6 : ASSERT_FALSE (g_toggle);
144 6 : ASSERT_EQ (v1, 10);
145 : }
146 :
147 : #if defined(__APPLE__)
148 : TEST (DISABLED_test_contextual_thread, activate)
149 : #else
150 20 : TEST (test_contextual_thread, activate)
151 : #endif
152 : {
153 4 : Key specKey ("/act/%activate%", KEY_CASCADING_NAME, KEY_END);
154 :
155 4 : KeySet ks;
156 6 : ks.append (Key ("user/act/%", KEY_VALUE, "10", KEY_END)); // not active layer
157 6 : ks.append (Key ("user/act/active", KEY_VALUE, "22", KEY_END));
158 :
159 4 : Coordinator gc;
160 4 : ThreadContext c (gc);
161 6 : ThreadValue<int> v (ks, c, specKey);
162 6 : ASSERT_EQ (v, 10);
163 8 : ASSERT_EQ (c.size (), 0);
164 14 : ASSERT_EQ (c["other"], "");
165 14 : ASSERT_EQ (c["activate"], "");
166 :
167 6 : std::thread t1 (activate1, std::ref (gc), std::ref (ks));
168 6 : ASSERT_EQ (v, 10);
169 4 : std::this_thread::sleep_for (std::chrono::milliseconds (100));
170 4 : ASSERT_TRUE (g_toggle);
171 2 : c.syncLayers ();
172 6 : ASSERT_EQ (v, 22);
173 2 : t1.join ();
174 6 : ASSERT_FALSE (g_toggle);
175 6 : ASSERT_EQ (v, 22);
176 4 : c.activate<Other> (); // also fetches updates
177 8 : ASSERT_EQ (c.size (), 1);
178 14 : ASSERT_EQ (c["other"], "notused");
179 14 : ASSERT_EQ (c["activate"], "");
180 6 : ASSERT_EQ (v, 10);
181 : }
182 :
183 : const uint32_t i_value = 55;
184 : const char * s_value = "55";
185 :
186 20 : TEST (test_contextual_thread, ThreadNoContext)
187 : {
188 : using namespace kdb;
189 4 : KeySet ks;
190 2 : ThreadNoContext c;
191 2 : const char * name = "/%language%/%country%/%dialect%/test";
192 18 : ASSERT_TRUE (!ks.lookup (name));
193 6 : Value<int, ContextPolicyIs<ThreadNoContext>> i (ks, c, Key (name, KEY_CASCADING_NAME, KEY_META, "default", s_value, KEY_END));
194 4 : ASSERT_EQ (i, i_value);
195 16 : ASSERT_TRUE (ks.lookup (name));
196 2 : i = 5;
197 6 : ASSERT_EQ (i, 5);
198 8 : ASSERT_EQ (i.getSpec ().getName (), name);
199 2 : i.syncKeySet ();
200 18 : ASSERT_EQ (ks.lookup (name).getString (), "5");
201 2 : i = 10;
202 6 : ASSERT_EQ (i, 10);
203 18 : ASSERT_EQ (ks.lookup (name).getString (), "10");
204 : }
205 :
206 :
207 : /**
208 : * @brief Dependent on layer Activate
209 : */
210 8 : class Dep : public kdb::Layer
211 : {
212 : public:
213 4 : explicit Dep (ThreadValue<int> const & i) : m_i (std::to_string (static_cast<int> (i)))
214 : {
215 : // capture current value of contextual value here
216 : }
217 24 : std::string id () const override
218 : {
219 72 : return "dep";
220 : }
221 8 : std::string operator() () const override
222 : {
223 16 : return m_i;
224 : }
225 : std::string m_i;
226 : };
227 :
228 :
229 20 : TEST (test_contextual_thread, activateNoDependency)
230 : {
231 4 : Key specKey ("/act/%activate%", KEY_CASCADING_NAME, KEY_END);
232 :
233 4 : KeySet ks;
234 6 : ks.append (Key ("user/act/%", KEY_VALUE, "10", KEY_END)); // not active layer
235 6 : ks.append (Key ("user/act/active", KEY_VALUE, "22", KEY_END));
236 :
237 4 : Coordinator gc;
238 4 : ThreadContext c1 (gc);
239 4 : ThreadContext c2 (gc);
240 6 : ThreadValue<int> v (ks, c1, specKey);
241 6 : ASSERT_EQ (v, 10);
242 8 : ASSERT_EQ (c1.size (), 0);
243 14 : ASSERT_EQ (c1["other"], "");
244 14 : ASSERT_EQ (c1["activate"], "");
245 :
246 4 : c2.activate<Dep> (v);
247 8 : ASSERT_EQ (c2.size (), 1);
248 14 : ASSERT_EQ (c2["dep"], "10");
249 4 : c2.activate<Activate> ();
250 8 : ASSERT_EQ (c2.size (), 2);
251 14 : ASSERT_EQ (c2["dep"], "10");
252 14 : ASSERT_EQ (c2["activate"], "active");
253 :
254 2 : c1.syncLayers ();
255 14 : ASSERT_EQ (c1["dep"], "10");
256 14 : ASSERT_EQ (c2["activate"], "active");
257 8 : ASSERT_EQ (v.getName (), "user/act/active");
258 6 : ASSERT_EQ (v, 22);
259 : }
260 :
261 :
262 20 : TEST (test_contextual_thread, activateWithDependency)
263 : {
264 4 : Key specKey ("/act/%activate%", KEY_CASCADING_NAME, KEY_END);
265 :
266 4 : KeySet ks;
267 6 : ks.append (Key ("user/act/%", KEY_VALUE, "10", KEY_END)); // not active layer
268 6 : ks.append (Key ("user/act/active", KEY_VALUE, "22", KEY_END));
269 :
270 4 : Coordinator gc;
271 4 : ThreadContext c1 (gc);
272 4 : ThreadContext c2 (gc);
273 6 : ThreadValue<int> v1 (ks, c1, specKey);
274 6 : ThreadValue<int> v2 (ks, c2, specKey);
275 6 : ASSERT_EQ (v1, 10);
276 6 : ASSERT_EQ (v2, 10);
277 :
278 8 : ASSERT_EQ (c1.size (), 0);
279 14 : ASSERT_EQ (c1["other"], "");
280 14 : ASSERT_EQ (c1["activate"], "");
281 :
282 8 : ASSERT_EQ (c2.size (), 0);
283 14 : ASSERT_EQ (c2["other"], "");
284 14 : ASSERT_EQ (c2["activate"], "");
285 :
286 4 : c2.activate<Activate> ();
287 8 : ASSERT_EQ (c2.size (), 1);
288 14 : ASSERT_EQ (c2["activate"], "active");
289 :
290 6 : ASSERT_EQ (v1, 10);
291 6 : ASSERT_EQ (v2, 22);
292 :
293 4 : c1.activate<Dep> (v1);
294 8 : ASSERT_EQ (c1.size (), 2);
295 14 : ASSERT_EQ (c1["dep"], "22") << "dependency not correct, activate does not do syncLayer";
296 14 : ASSERT_EQ (c1["activate"], "active");
297 14 : ASSERT_EQ (c2["activate"], "active");
298 : }
299 :
300 4 : class StrDep : public kdb::Layer
301 : {
302 : public:
303 2 : explicit StrDep (ThreadValue<std::string> const & i) : m_i (i)
304 : {
305 : }
306 10 : std::string id () const override
307 : {
308 30 : return "dep";
309 : }
310 0 : std::string operator() () const override
311 : {
312 0 : return m_i;
313 : }
314 : std::string m_i;
315 : };
316 :
317 :
318 20 : TEST (test_contextual_thread, activateWithDirectDependency)
319 : {
320 4 : Key specKey ("/act/%activate%", KEY_END);
321 :
322 4 : KeySet ks;
323 6 : ks.append (Key ("user/act/%", KEY_VALUE, "inactive", KEY_END));
324 6 : ks.append (Key ("user/act/active", KEY_VALUE, "active", KEY_END));
325 :
326 4 : Coordinator gc;
327 4 : ThreadContext c1 (gc);
328 4 : ThreadContext c2 (gc);
329 6 : ThreadValue<std::string> v1 (ks, c1, specKey);
330 6 : ThreadValue<std::string> v2 (ks, c2, specKey);
331 6 : ThreadValue<std::string> vd (ks, c2, specKey);
332 8 : ASSERT_EQ (std::string (v1), "inactive");
333 8 : ASSERT_EQ (std::string (v2), "inactive");
334 8 : ASSERT_EQ (std::string (vd), "inactive");
335 :
336 4 : c1.activate<Activate> ();
337 8 : ASSERT_EQ (std::string (v1), "active");
338 8 : ASSERT_EQ (std::string (v2), "inactive");
339 8 : ASSERT_EQ (std::string (vd), "inactive");
340 :
341 4 : c2.activate<StrDep> (vd);
342 8 : ASSERT_EQ (std::string (v1), "active");
343 8 : ASSERT_EQ (std::string (v2), "active");
344 8 : ASSERT_EQ (std::string (vd), "active");
345 : }
346 :
347 :
348 20 : TEST (test_contextual_thread, syncInWith)
349 : {
350 4 : Key specKey ("/act/%activate%", KEY_CASCADING_NAME, KEY_END);
351 :
352 4 : KeySet ks;
353 6 : ks.append (Key ("user/act/%", KEY_VALUE, "10", KEY_END)); // not active layer
354 6 : ks.append (Key ("user/act/active", KEY_VALUE, "22", KEY_END));
355 :
356 4 : Coordinator gc;
357 4 : ThreadContext c1 (gc);
358 4 : ThreadContext c2 (gc);
359 6 : ThreadValue<int> v (ks, c1, specKey);
360 6 : ASSERT_EQ (v, 10);
361 8 : ASSERT_EQ (c1.size (), 0);
362 14 : ASSERT_EQ (c1["other"], "");
363 14 : ASSERT_EQ (c1["activate"], "");
364 :
365 4 : c2.activate<Activate> ();
366 8 : ASSERT_EQ (c2.size (), 1);
367 14 : ASSERT_EQ (c2["activate"], "active");
368 :
369 4 : c1.with<Other> () ([&]() {
370 20 : ASSERT_EQ (c1.size (), 1);
371 16 : ASSERT_EQ (c1["other"], "notused");
372 16 : ASSERT_EQ (c1["activate"], "");
373 16 : ASSERT_EQ (v.getName (), "user/act/%");
374 6 : ASSERT_EQ (v, 10);
375 :
376 2 : c1.syncLayers ();
377 :
378 10 : ASSERT_EQ (c1.size (), 2);
379 16 : ASSERT_EQ (c1["other"], "notused");
380 16 : ASSERT_EQ (c1["activate"], "active");
381 8 : ASSERT_EQ (v.getName (), "user/act/active");
382 6 : ASSERT_EQ (v, 22);
383 8 : });
384 :
385 8 : ASSERT_EQ (c1.size (), 1);
386 14 : ASSERT_EQ (c1["other"], "");
387 14 : ASSERT_EQ (c1["activate"], "active");
388 8 : ASSERT_EQ (v.getName (), "user/act/active");
389 6 : ASSERT_EQ (v, 22);
390 : }
391 :
392 :
393 20 : TEST (test_contextual_thread, syncBeforeWith)
394 : {
395 4 : Key specKey ("/act/%activate%", KEY_CASCADING_NAME, KEY_END);
396 :
397 4 : KeySet ks;
398 6 : ks.append (Key ("user/act/%", KEY_VALUE, "10", KEY_END)); // not active layer
399 6 : ks.append (Key ("user/act/active", KEY_VALUE, "22", KEY_END));
400 :
401 4 : Coordinator gc;
402 4 : ThreadContext c1 (gc);
403 4 : ThreadContext c2 (gc);
404 6 : ThreadValue<int> v (ks, c1, specKey);
405 6 : ASSERT_EQ (v, 10);
406 8 : ASSERT_EQ (c1.size (), 0);
407 14 : ASSERT_EQ (c1["other"], "");
408 14 : ASSERT_EQ (c1["activate"], "");
409 :
410 4 : c2.activate<Activate> ();
411 8 : ASSERT_EQ (c2.size (), 1);
412 14 : ASSERT_EQ (c2["activate"], "active");
413 :
414 2 : c1.syncLayers ();
415 8 : ASSERT_EQ (c1.size (), 1);
416 14 : ASSERT_EQ (c1["other"], "");
417 14 : ASSERT_EQ (c1["activate"], "active");
418 8 : ASSERT_EQ (v.getName (), "user/act/active");
419 6 : ASSERT_EQ (v, 22);
420 :
421 4 : c1.with<Other> () ([&]() {
422 12 : ASSERT_EQ (c1.size (), 2);
423 16 : ASSERT_EQ (c1["other"], "notused");
424 16 : ASSERT_EQ (c1["activate"], "active");
425 12 : ASSERT_EQ (v.getName (), "user/act/active");
426 6 : ASSERT_EQ (v, 22);
427 8 : });
428 :
429 8 : ASSERT_EQ (c1.size (), 1);
430 14 : ASSERT_EQ (c1["other"], "");
431 14 : ASSERT_EQ (c1["activate"], "active");
432 8 : ASSERT_EQ (v.getName (), "user/act/active");
433 6 : ASSERT_EQ (v, 22);
434 6 : }
|