1 /*
2  * Copyright 2013 MongoDB, Inc.
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 
18 #include <bson.h>
19 #define BSON_INSIDE
20 #include "bson-thread-private.h"
21 #undef BSON_INSIDE
22 #include <ctype.h>
23 #include <fcntl.h>
24 #include <time.h>
25 
26 #ifdef HAVE_STRINGS_H
27 #include <strings.h>
28 #endif
29 
30 #include "bson-tests.h"
31 #include "TestSuite.h"
32 
33 #define N_THREADS 4
34 
35 static const char *gTestOids[] = {"000000000000000000000000",
36                                   "010101010101010101010101",
37                                   "0123456789abcdefafcdef03",
38                                   "fcdeab182763817236817236",
39                                   "ffffffffffffffffffffffff",
40                                   "eeeeeeeeeeeeeeeeeeeeeeee",
41                                   "999999999999999999999999",
42                                   "111111111111111111111111",
43                                   NULL};
44 
45 static const char *gTestOidsCase[] = {"0123456789ABCDEFAFCDEF03",
46                                       "FCDEAB182763817236817236",
47                                       "FFFFFFFFFFFFFFFFFFFFFFFF",
48                                       "EEEEEEEEEEEEEEEEEEEEEEEE",
49                                       "01234567890ACBCDEFabcdef",
50                                       NULL};
51 
52 static const char *gTestOidsFail[] = {"                        ",
53                                       "abasdf                  ",
54                                       "asdfasdfasdfasdfasdf    ",
55                                       "00000000000000000000000z",
56                                       "00187263123ghh21382812a8",
57                                       NULL};
58 
59 static void *
oid_worker(void * data)60 oid_worker (void *data)
61 {
62    bson_context_t *context = data;
63    bson_oid_t oid;
64    bson_oid_t oid2;
65    int i;
66 
67    bson_oid_init (&oid2, context);
68    for (i = 0; i < 500000; i++) {
69       bson_oid_init (&oid, context);
70       BSON_ASSERT (false == bson_oid_equal (&oid, &oid2));
71       BSON_ASSERT (0 < bson_oid_compare (&oid, &oid2));
72       bson_oid_copy (&oid, &oid2);
73    }
74 
75    return NULL;
76 }
77 
78 static void
test_bson_oid_init_from_string(void)79 test_bson_oid_init_from_string (void)
80 {
81    bson_context_t *context;
82    bson_oid_t oid;
83    char str[25];
84    int i;
85 
86    context = bson_context_new (BSON_CONTEXT_NONE);
87 
88    /*
89     * Test successfully parsed oids.
90     */
91 
92    for (i = 0; gTestOids[i]; i++) {
93       bson_oid_init_from_string (&oid, gTestOids[i]);
94       bson_oid_to_string (&oid, str);
95       BSON_ASSERT (!strcmp (str, gTestOids[i]));
96    }
97 
98    /*
99     * Test successfully parsed oids (case-insensitive).
100     */
101    for (i = 0; gTestOidsCase[i]; i++) {
102       char oid_lower[25];
103       int j;
104 
105       bson_oid_init_from_string (&oid, gTestOidsCase[i]);
106       bson_oid_to_string (&oid, str);
107       BSON_ASSERT (!bson_strcasecmp (str, gTestOidsCase[i]));
108 
109       for (j = 0; gTestOidsCase[i][j]; j++) {
110          oid_lower[j] = tolower (gTestOidsCase[i][j]);
111       }
112 
113       oid_lower[24] = '\0';
114       BSON_ASSERT (!strcmp (str, oid_lower));
115    }
116 
117    /*
118     * Test that sizeof(str) works (len of 25 with \0 instead of 24).
119     */
120    BSON_ASSERT (bson_oid_is_valid ("ffffffffffffffffffffffff", 24));
121    bson_oid_init_from_string (&oid, "ffffffffffffffffffffffff");
122    bson_oid_to_string (&oid, str);
123    BSON_ASSERT (bson_oid_is_valid (str, sizeof str));
124 
125    /*
126     * Test the failures.
127     */
128 
129    for (i = 0; gTestOidsFail[i]; i++) {
130       bson_oid_init_from_string (&oid, gTestOidsFail[i]);
131       bson_oid_to_string (&oid, str);
132       BSON_ASSERT (strcmp (str, gTestOidsFail[i]));
133    }
134 
135    bson_context_destroy (context);
136 }
137 
138 
139 static void
test_bson_oid_hash(void)140 test_bson_oid_hash (void)
141 {
142    bson_oid_t oid;
143 
144    bson_oid_init_from_string (&oid, "000000000000000000000000");
145    BSON_ASSERT (bson_oid_hash (&oid) == 1487062149);
146 }
147 
148 
149 static void
test_bson_oid_compare(void)150 test_bson_oid_compare (void)
151 {
152    bson_oid_t oid;
153    bson_oid_t oid2;
154 
155    bson_oid_init_from_string (&oid, "000000000000000000001234");
156    bson_oid_init_from_string (&oid2, "000000000000000000001234");
157    BSON_ASSERT (0 == bson_oid_compare (&oid, &oid2));
158    BSON_ASSERT (true == bson_oid_equal (&oid, &oid2));
159 
160    bson_oid_init_from_string (&oid, "000000000000000000001234");
161    bson_oid_init_from_string (&oid2, "000000000000000000004321");
162    BSON_ASSERT (bson_oid_compare (&oid, &oid2) < 0);
163    BSON_ASSERT (bson_oid_compare (&oid2, &oid) > 0);
164    BSON_ASSERT (false == bson_oid_equal (&oid, &oid2));
165 }
166 
167 
168 static void
test_bson_oid_copy(void)169 test_bson_oid_copy (void)
170 {
171    bson_oid_t oid;
172    bson_oid_t oid2;
173 
174    bson_oid_init_from_string (&oid, "000000000000000000001234");
175    bson_oid_init_from_string (&oid2, "000000000000000000004321");
176    bson_oid_copy (&oid, &oid2);
177    BSON_ASSERT (true == bson_oid_equal (&oid, &oid2));
178 }
179 
180 
181 static void
test_bson_oid_init(void)182 test_bson_oid_init (void)
183 {
184    bson_context_t *context;
185    bson_oid_t oid;
186    bson_oid_t oid2;
187    int i;
188 
189    context = bson_context_new (BSON_CONTEXT_NONE);
190    bson_oid_init (&oid, context);
191    for (i = 0; i < 10000; i++) {
192       bson_oid_init (&oid2, context);
193       BSON_ASSERT (false == bson_oid_equal (&oid, &oid2));
194       BSON_ASSERT (0 > bson_oid_compare (&oid, &oid2));
195       bson_oid_copy (&oid2, &oid);
196    }
197    bson_context_destroy (context);
198 
199    /*
200     * Test that the shared context works.
201     */
202    bson_oid_init (&oid, NULL);
203    BSON_ASSERT (bson_context_get_default ());
204 }
205 
206 
207 static void
test_bson_oid_init_sequence(void)208 test_bson_oid_init_sequence (void)
209 {
210    bson_context_t *context;
211    bson_oid_t oid;
212    bson_oid_t oid2;
213    int i;
214 
215    context = bson_context_new (BSON_CONTEXT_NONE);
216    bson_oid_init_sequence (&oid, context);
217    for (i = 0; i < 10000; i++) {
218       bson_oid_init_sequence (&oid2, context);
219       BSON_ASSERT (false == bson_oid_equal (&oid, &oid2));
220       BSON_ASSERT (0 > bson_oid_compare (&oid, &oid2));
221       bson_oid_copy (&oid2, &oid);
222    }
223    bson_context_destroy (context);
224 }
225 
226 
227 static void
test_bson_oid_init_sequence_thread_safe(void)228 test_bson_oid_init_sequence_thread_safe (void)
229 {
230    bson_context_t *context;
231    bson_oid_t oid;
232    bson_oid_t oid2;
233    int i;
234 
235    context = bson_context_new (BSON_CONTEXT_THREAD_SAFE);
236    bson_oid_init_sequence (&oid, context);
237    for (i = 0; i < 10000; i++) {
238       bson_oid_init_sequence (&oid2, context);
239       BSON_ASSERT (false == bson_oid_equal (&oid, &oid2));
240       BSON_ASSERT (0 > bson_oid_compare (&oid, &oid2));
241       bson_oid_copy (&oid2, &oid);
242    }
243    bson_context_destroy (context);
244 }
245 
246 
247 #ifdef BSON_HAVE_SYSCALL_TID
248 static void
test_bson_oid_init_sequence_with_tid(void)249 test_bson_oid_init_sequence_with_tid (void)
250 {
251    bson_context_t *context;
252    bson_oid_t oid;
253    bson_oid_t oid2;
254    int i;
255 
256    context = bson_context_new (BSON_CONTEXT_USE_TASK_ID);
257    bson_oid_init_sequence (&oid, context);
258    for (i = 0; i < 10000; i++) {
259       bson_oid_init_sequence (&oid2, context);
260       BSON_ASSERT (false == bson_oid_equal (&oid, &oid2));
261       BSON_ASSERT (0 > bson_oid_compare (&oid, &oid2));
262       bson_oid_copy (&oid2, &oid);
263    }
264    bson_context_destroy (context);
265 }
266 #endif
267 
268 
269 static void
test_bson_oid_get_time_t(void)270 test_bson_oid_get_time_t (void)
271 {
272    bson_context_t *context;
273    bson_oid_t oid;
274    bson_oid_t oid2;
275 
276    /*
277     * Test that the bson time_t matches the current time. This can race, but
278     * i dont think that matters much.
279     */
280    context = bson_context_new (BSON_CONTEXT_NONE);
281    bson_oid_init (&oid, context);
282    bson_oid_init (&oid2, context);
283    BSON_ASSERT (bson_oid_get_time_t (&oid) == bson_oid_get_time_t (&oid2));
284    BSON_ASSERT (time (NULL) == bson_oid_get_time_t (&oid2));
285    bson_context_destroy (context);
286 }
287 
288 
289 static void
test_bson_oid_init_with_threads(void)290 test_bson_oid_init_with_threads (void)
291 {
292    bson_context_t *context;
293    int i;
294 
295    {
296       bson_context_flags_t flags = 0;
297       bson_context_t *contexts[N_THREADS];
298       bson_thread_t threads[N_THREADS];
299 
300 #ifdef BSON_HAVE_SYSCALL_TID
301       flags |= BSON_CONTEXT_USE_TASK_ID;
302 #endif
303 
304       for (i = 0; i < N_THREADS; i++) {
305          contexts[i] = bson_context_new (flags);
306          bson_thread_create (&threads[i], oid_worker, contexts[i]);
307       }
308 
309       for (i = 0; i < N_THREADS; i++) {
310          bson_thread_join (threads[i]);
311       }
312 
313       for (i = 0; i < N_THREADS; i++) {
314          bson_context_destroy (contexts[i]);
315       }
316    }
317 
318    /*
319     * Test threaded generation of oids using a single context;
320     */
321    {
322       bson_thread_t threads[N_THREADS];
323 
324       context = bson_context_new (BSON_CONTEXT_THREAD_SAFE);
325 
326       for (i = 0; i < N_THREADS; i++) {
327          bson_thread_create (&threads[i], oid_worker, context);
328       }
329 
330       for (i = 0; i < N_THREADS; i++) {
331          bson_thread_join (threads[i]);
332       }
333 
334       bson_context_destroy (context);
335    }
336 }
337 
338 void
test_oid_install(TestSuite * suite)339 test_oid_install (TestSuite *suite)
340 {
341    TestSuite_Add (suite, "/bson/oid/init", test_bson_oid_init);
342    TestSuite_Add (
343       suite, "/bson/oid/init_from_string", test_bson_oid_init_from_string);
344    TestSuite_Add (
345       suite, "/bson/oid/init_sequence", test_bson_oid_init_sequence);
346    TestSuite_Add (suite,
347                   "/bson/oid/init_sequence_thread_safe",
348                   test_bson_oid_init_sequence_thread_safe);
349 #ifdef BSON_HAVE_SYSCALL_TID
350    TestSuite_Add (suite,
351                   "/bson/oid/init_sequence_with_tid",
352                   test_bson_oid_init_sequence_with_tid);
353 #endif
354    TestSuite_Add (
355       suite, "/bson/oid/init_with_threads", test_bson_oid_init_with_threads);
356    TestSuite_Add (suite, "/bson/oid/hash", test_bson_oid_hash);
357    TestSuite_Add (suite, "/bson/oid/compare", test_bson_oid_compare);
358    TestSuite_Add (suite, "/bson/oid/copy", test_bson_oid_copy);
359    TestSuite_Add (suite, "/bson/oid/get_time_t", test_bson_oid_get_time_t);
360 }
361