]> git.saurik.com Git - apple/configd.git/blob - sctest/SCTestDynamicStore.m
configd-1109.40.9.tar.gz
[apple/configd.git] / sctest / SCTestDynamicStore.m
1 /*
2 * Copyright (c) 2016, 2017 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #import "SCTest.h"
25 #import "SCTestUtils.h"
26
27 @interface SCTestDynamicStore : SCTest
28 @property SCDynamicStoreRef store;
29 @property dispatch_semaphore_t sem;
30 @property int counter;
31 @end
32
33 @implementation SCTestDynamicStore
34
35 + (NSString *)command
36 {
37 return @"dynamic_store";
38 }
39
40 + (NSString *)commandDescription
41 {
42 return @"Tests the SCDynamicStore code path";
43 }
44
45 - (instancetype)initWithOptions:(NSDictionary *)options
46 {
47 self = [super initWithOptions:options];
48 if (self) {
49 _store = SCDynamicStoreCreate(kCFAllocatorDefault,
50 CFSTR("SCTest"),
51 NULL,
52 NULL);
53 if (_store == NULL) {
54 SCTestLog("Could not create session");
55 ERR_EXIT;
56 }
57 }
58 return self;
59 }
60
61 - (void)dealloc
62 {
63 if (self.store != NULL) {
64 CFRelease(self.store);
65 self.store = NULL;
66 }
67 }
68
69 - (void)start
70 {
71 CFStringRef key;
72 if (self.options[kSCTestDynamicStoreOptionDNS]) {
73 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault, kSCDynamicStoreDomainState, kSCEntNetDNS);
74 CFPropertyListRef value = SCDynamicStoreCopyValue(self.store, key);
75 SCTestLog("%@ : %@", key, value);
76 CFRelease(key);
77 if (value != NULL) {
78 CFRelease(value);
79 }
80 }
81
82 if (self.options[kSCTestDynamicStoreOptionIPv4]) {
83 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault, kSCDynamicStoreDomainState, kSCEntNetIPv4);
84 CFPropertyListRef value = SCDynamicStoreCopyValue(self.store, key);
85 SCTestLog("%@ : %@", key, value);
86 CFRelease(key);
87 if (value != NULL) {
88 CFRelease(value);
89 }
90 }
91
92 if (self.options[kSCTestDynamicStoreOptionIPv6]) {
93 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault, kSCDynamicStoreDomainState, kSCEntNetIPv6);
94 CFPropertyListRef value = SCDynamicStoreCopyValue(self.store, key);
95 SCTestLog("%@ : %@", key, value);
96 CFRelease(key);
97 if (value != NULL) {
98 CFRelease(value);
99 }
100 }
101
102 if (self.options[kSCTestDynamicStoreOptionProxies]) {
103 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault, kSCDynamicStoreDomainState, kSCEntNetProxies);
104 CFPropertyListRef value = SCDynamicStoreCopyValue(self.store, key);
105 SCTestLog("%@ : %@", key, value);
106 CFRelease(key);
107 if (value != NULL) {
108 CFRelease(value);
109 }
110 }
111
112 [self cleanupAndExitWithErrorCode:0];
113 }
114
115 - (void)cleanupAndExitWithErrorCode:(int)error
116 {
117 [super cleanupAndExitWithErrorCode:error];
118 }
119
120 - (BOOL)setup
121 {
122 return YES;
123 }
124
125 - (BOOL)unitTest
126 {
127 if(![self setup]) {
128 return NO;
129 }
130
131 BOOL allUnitTestsPassed = YES;
132 allUnitTestsPassed &= [self unitTestSetAndRemoveValue];
133 allUnitTestsPassed &= [self unitTestCopyMultiple];
134 allUnitTestsPassed &= [self unitTestSCDynamicStoreCallbackStress];
135 allUnitTestsPassed &= [self unitTestSCDynamicStoreSetMultipleStress];
136
137 if(![self tearDown]) {
138 return NO;
139 }
140
141 return allUnitTestsPassed;
142 }
143
144 - (BOOL)tearDown
145 {
146 return YES;
147 }
148
149 - (BOOL)unitTestSetAndRemoveValue
150 {
151 int iterations = 1000;
152 NSDictionary *bogusValue;
153 SCTestDynamicStore *test;
154
155 test = [[SCTestDynamicStore alloc] initWithOptions:self.options];
156 bogusValue = @{@"Pretty":@"Useless"};
157
158 for (int i = 0; i < iterations; i++) {
159 NSUUID *uuid = [NSUUID UUID];
160 CFStringRef key;
161 BOOL ok;
162
163 key = SCDynamicStoreKeyCreateNetworkServiceEntity(kCFAllocatorDefault,
164 CFSTR("SCTest"),
165 (__bridge CFStringRef)uuid.UUIDString,
166 kSCEntNetDNS);
167 ok = SCDynamicStoreSetValue(test.store, key, (__bridge CFDictionaryRef)bogusValue);
168 if (!ok) {
169 SCTestLog("Failed to set value in SCDynamicStore. Error: %s", SCErrorString(SCError()));
170 CFRelease(key);
171 return NO;
172 }
173
174 ok = SCDynamicStoreRemoveValue(test.store, key);
175 if (!ok) {
176 SCTestLog("Failed to remove value from SCDynamicStore. Error: %s", SCErrorString(SCError()));
177 CFRelease(key);
178 return NO;
179 }
180
181 CFRelease(key);
182 }
183
184 SCTestLog("Successfully completed setAndRemove unit test");
185 return YES;
186 }
187
188 - (BOOL)unitTestCopyMultiple
189 {
190 NSString *pattern;
191 SCTestDynamicStore *test;
192 CFArrayRef keyList;
193 int iterations = 1000;
194
195 test = [[SCTestDynamicStore alloc] initWithOptions:self.options];
196 pattern = (__bridge_transfer NSString *)SCDynamicStoreKeyCreate(kCFAllocatorDefault,
197 CFSTR("%@/%@/%@/%@/%@"),
198 kSCDynamicStoreDomainState,
199 kSCCompNetwork,
200 kSCCompInterface,
201 kSCCompAnyRegex,
202 kSCCompAnyRegex);
203
204 keyList = SCDynamicStoreCopyKeyList(test.store, (__bridge CFStringRef)pattern);
205 for (int i = 0; i < iterations; i++) {
206 CFDictionaryRef value = SCDynamicStoreCopyMultiple(test.store, keyList, NULL);
207 if (value == NULL) {
208 SCTestLog("Failed to copy multiple values from SCDynamicStore. Error: %s", SCErrorString(SCError()));
209 CFRelease(keyList);
210 return NO;
211 }
212 CFRelease(value);
213 }
214 CFRelease(keyList);
215
216 pattern = (__bridge_transfer NSString *)SCDynamicStoreKeyCreate(kCFAllocatorDefault,
217 CFSTR("%@/%@/%@/%@/%@"),
218 kSCDynamicStoreDomainSetup,
219 kSCCompNetwork,
220 kSCCompService,
221 kSCCompAnyRegex,
222 kSCCompAnyRegex);
223
224 keyList = SCDynamicStoreCopyKeyList(test.store, (__bridge CFStringRef)pattern);
225 for (int i = 0; i < iterations; i++) {
226 CFDictionaryRef value = SCDynamicStoreCopyMultiple(test.store, keyList, NULL);
227 if (value == NULL) {
228 SCTestLog("Failed to copy multiple values from SCDynamicStore. Error: %s", SCErrorString(SCError()));
229 CFRelease(keyList);
230 return NO;
231 }
232 CFRelease(value);
233 }
234 CFRelease(keyList);
235
236 SCTestLog("Successfully completed copyMultiple unit test");
237 return YES;
238 }
239
240 void
241 myTestCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void *ctx)
242 {
243 #pragma unused(store)
244 #pragma unused(changedKeys)
245 SCTestDynamicStore *test = (__bridge SCTestDynamicStore *)ctx;
246 test.counter++;
247 if (test.sem != NULL) {
248 dispatch_semaphore_signal(test.sem);
249 }
250 }
251
252 - (BOOL)unitTestSCDynamicStoreCallbackStress
253 {
254 SCTestDynamicStore *test;
255 int iterations = 100;
256 NSString *testKey = @"State:/myTestKey";
257 BOOL ok;
258 dispatch_queue_t callbackQ;
259
260 test = [[SCTestDynamicStore alloc] initWithOptions:self.options];
261 if (test.store != NULL) {
262 CFRelease(test.store);
263 test.store = NULL;
264 }
265
266 SCDynamicStoreContext ctx = {0, (__bridge void * _Nullable)(test), CFRetain, CFRelease, NULL};
267 test.store = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("SCTest"), myTestCallback, &ctx);
268
269 ok = SCDynamicStoreSetNotificationKeys(test.store, (__bridge CFArrayRef)@[testKey], NULL);
270 if (!ok) {
271 SCTestLog("Failed to set notification keys. Error: %s", SCErrorString(SCError()));
272 return NO;
273 }
274
275 callbackQ = dispatch_queue_create("SCTestDynamicStore callback queue", NULL);
276 ok = SCDynamicStoreSetDispatchQueue(test.store, callbackQ);
277 if (!ok) {
278 SCTestLog("Failed to set dispatch queue. Error: %s", SCErrorString(SCError()));
279 return NO;
280 }
281
282 for (int i = 0; i < iterations; i++) {
283 NSUUID *uuid = [NSUUID UUID];
284 ok = SCDynamicStoreSetValue(test.store, (__bridge CFStringRef)testKey, (__bridge CFStringRef)uuid.UUIDString);
285 if (!ok) {
286 SCTestLog("Failed to set value. Error: %s", SCErrorString(SCError()));
287 return NO;
288 }
289 // Perform a write to Dynamic Store every 10ms.
290 [test waitFor:0.01];
291 }
292
293 ok = SCDynamicStoreRemoveValue(test.store, (__bridge CFStringRef)testKey);
294 if (!ok) {
295 SCTestLog("Failed to remove value. Error: %s", SCErrorString(SCError()));
296 return NO;
297 }
298
299 if (test.counter < iterations) {
300 // Not all callbacks were received
301 SCTestLog("Not all SCDynamicStore callbacks were received (%d/%d). Something went wrong", test.counter, iterations);
302 return NO;
303 }
304
305 SCTestLog("Successfully completed SCDynamicStore callbacks unit test");
306 return YES;
307 }
308
309 - (BOOL)unitTestSCDynamicStoreSetMultipleStress
310 {
311 SCTestDynamicStore *test;
312 int iterations = 100;
313 NSMutableArray *testKeyArray;
314 NSMutableDictionary *testSetDictionary;
315 int expectedCallbackCount = 0;
316 BOOL ok;
317 dispatch_queue_t callbackQ;
318 uint8_t waitTime = 1; // second
319
320 test = [[SCTestDynamicStore alloc] initWithOptions:self.options];
321 if (test.store != NULL) {
322 CFRelease(test.store);
323 test.store = NULL;
324 }
325
326 SCDynamicStoreContext ctx = {0, (__bridge void * _Nullable)(test), CFRetain, CFRelease, NULL};
327 test.store = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("SCTest"), myTestCallback, &ctx);
328 test.sem = dispatch_semaphore_create(0);
329
330 testKeyArray = [[NSMutableArray alloc] init];
331
332 for (int i = 0; i < iterations; i++) {
333 NSUUID *uuid = [NSUUID UUID];
334 NSString *str = [NSString stringWithFormat:@"State:/%@", uuid];
335 [testKeyArray addObject:str];
336 }
337
338 testSetDictionary = [[NSMutableDictionary alloc] init];
339 for (NSString *key in testKeyArray) {
340 NSUUID *uuid = [NSUUID UUID];
341 [testSetDictionary setObject:@[uuid.UUIDString] forKey:key];
342 }
343
344 callbackQ = dispatch_queue_create("SCTestDynamicStore callback queue", NULL);
345 ok = SCDynamicStoreSetNotificationKeys(test.store, (__bridge CFArrayRef)testKeyArray, NULL);
346 if (!ok) {
347 SCTestLog("Failed to set notification keys. Error: %s", SCErrorString(SCError()));
348 return NO;
349 }
350
351 ok = SCDynamicStoreSetDispatchQueue(test.store, callbackQ);
352 if (!ok) {
353 SCTestLog("Failed to set dispatch queue. Error: %s", SCErrorString(SCError()));
354 return NO;
355 }
356
357 ok = SCDynamicStoreSetMultiple(test.store, (__bridge CFDictionaryRef)testSetDictionary, NULL, NULL);
358 if (!ok) {
359 SCTestLog("Failed to set multiple keys. Error: %s", SCErrorString(SCError()));
360 return NO;
361 } else {
362 expectedCallbackCount++; // One callback for set multiple
363 }
364
365 if(dispatch_semaphore_wait(test.sem, dispatch_time(DISPATCH_TIME_NOW, waitTime * NSEC_PER_SEC))) {
366 SCTestLog("Failed to get a callback when multiple keys are set");
367 return NO;
368 }
369
370 ok = SCDynamicStoreSetMultiple(test.store, NULL, NULL, (__bridge CFArrayRef)testKeyArray);
371 if (!ok) {
372 SCTestLog("Failed to set multiple keys. Error: %s", SCErrorString(SCError()));
373 return NO;
374 } else {
375 expectedCallbackCount++; // One callback for fake notification
376 }
377
378 if(dispatch_semaphore_wait(test.sem, dispatch_time(DISPATCH_TIME_NOW, waitTime * NSEC_PER_SEC))) {
379 SCTestLog("Failed to get a callback when multiple keys are notified");
380 return NO;
381 }
382
383 ok = SCDynamicStoreSetMultiple(test.store, NULL, (__bridge CFArrayRef)testKeyArray, NULL);
384 if (!ok) {
385 SCTestLog("Failed to set multiple keys. Error: %s", SCErrorString(SCError()));
386 return NO;
387 } else {
388 expectedCallbackCount++; // One callback for key removal
389 }
390
391 if(dispatch_semaphore_wait(test.sem, dispatch_time(DISPATCH_TIME_NOW, waitTime * NSEC_PER_SEC))) {
392 SCTestLog("Failed to get a callback when multiple keys are removed");
393 return NO;
394 }
395
396 if (test.counter < expectedCallbackCount) {
397 // Not all callbacks were received
398 SCTestLog("Not all SCDynamicStore callbacks were received (%d/%d). Something went wrong", test.counter, expectedCallbackCount);
399 return NO;
400 }
401
402 SCTestLog("Successfully completed SCDynamicStore set multiple unit test");
403 return YES;
404
405 }
406
407
408 @end