]> git.saurik.com Git - apple/configd.git/blob - sctest/SCTestDynamicStore.m
configd-888.51.2.tar.gz
[apple/configd.git] / sctest / SCTestDynamicStore.m
1 /*
2 * Copyright (c) 2016 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 }
78
79 if (self.options[kSCTestDynamicStoreOptionIPv4]) {
80 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault, kSCDynamicStoreDomainState, kSCEntNetIPv4);
81 CFPropertyListRef value = SCDynamicStoreCopyValue(self.store, key);
82 SCTestLog("%@ : %@", key, value);
83 CFRelease(key);
84 }
85
86 if (self.options[kSCTestDynamicStoreOptionIPv6]) {
87 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault, kSCDynamicStoreDomainState, kSCEntNetIPv6);
88 CFPropertyListRef value = SCDynamicStoreCopyValue(self.store, key);
89 SCTestLog("%@ : %@", key, value);
90 CFRelease(key);
91 }
92
93 if (self.options[kSCTestDynamicStoreOptionProxies]) {
94 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault, kSCDynamicStoreDomainState, kSCEntNetProxies);
95 CFPropertyListRef value = SCDynamicStoreCopyValue(self.store, key);
96 SCTestLog("%@ : %@", key, value);
97 CFRelease(key);
98 }
99
100 [self cleanupAndExitWithErrorCode:0];
101 }
102
103 - (void)cleanupAndExitWithErrorCode:(int)error
104 {
105 [super cleanupAndExitWithErrorCode:error];
106 }
107
108 - (BOOL)setup
109 {
110 return YES;
111 }
112
113 - (BOOL)unitTest
114 {
115 if(![self setup]) {
116 return NO;
117 }
118
119 BOOL allUnitTestsPassed = YES;
120 allUnitTestsPassed &= [self unitTestSetAndRemoveValue];
121 allUnitTestsPassed &= [self unitTestCopyMultiple];
122 allUnitTestsPassed &= [self unitTestSCDynamicStoreCallbackStress];
123 allUnitTestsPassed &= [self unitTestSCDynamicStoreSetMultipleStress];
124
125 if(![self tearDown]) {
126 return NO;
127 }
128
129 return allUnitTestsPassed;
130 }
131
132 - (BOOL)tearDown
133 {
134 return YES;
135 }
136
137 - (BOOL)unitTestSetAndRemoveValue
138 {
139 int iterations = 1000;
140 NSDictionary *bogusValue;
141 SCTestDynamicStore *test;
142
143 test = [[SCTestDynamicStore alloc] initWithOptions:self.options];
144 bogusValue = @{@"Pretty":@"Useless"};
145
146 for (int i = 0; i < iterations; i++) {
147 NSUUID *uuid = [NSUUID UUID];
148 CFStringRef key;
149 BOOL ok;
150
151 key = SCDynamicStoreKeyCreateNetworkServiceEntity(kCFAllocatorDefault,
152 CFSTR("SCTest"),
153 (__bridge CFStringRef)uuid.UUIDString,
154 kSCEntNetDNS);
155 ok = SCDynamicStoreSetValue(test.store, key, (__bridge CFDictionaryRef)bogusValue);
156 if (!ok) {
157 SCTestLog("Failed to set value in SCDynamicStore. Error: %s", SCErrorString(SCError()));
158 CFRelease(key);
159 return NO;
160 }
161
162 ok = SCDynamicStoreRemoveValue(test.store, key);
163 if (!ok) {
164 SCTestLog("Failed to remove value from SCDynamicStore. Error: %s", SCErrorString(SCError()));
165 CFRelease(key);
166 return NO;
167 }
168
169 CFRelease(key);
170 }
171
172 SCTestLog("Successfully completed setAndRemove unit test");
173 return YES;
174 }
175
176 - (BOOL)unitTestCopyMultiple
177 {
178 NSString *pattern;
179 SCTestDynamicStore *test;
180 CFArrayRef keyList;
181 int iterations = 1000;
182
183 test = [[SCTestDynamicStore alloc] initWithOptions:self.options];
184 pattern = (__bridge_transfer NSString *)SCDynamicStoreKeyCreate(kCFAllocatorDefault,
185 CFSTR("%@/%@/%@/%@/%@"),
186 kSCDynamicStoreDomainState,
187 kSCCompNetwork,
188 kSCCompInterface,
189 kSCCompAnyRegex,
190 kSCCompAnyRegex);
191
192 keyList = SCDynamicStoreCopyKeyList(test.store, (__bridge CFStringRef)pattern);
193 for (int i = 0; i < iterations; i++) {
194 CFDictionaryRef value = SCDynamicStoreCopyMultiple(test.store, keyList, NULL);
195 if (value == NULL) {
196 SCTestLog("Failed to copy multiple values from SCDynamicStore. Error: %s", SCErrorString(SCError()));
197 CFRelease(keyList);
198 return NO;
199 }
200 CFRelease(value);
201 }
202 CFRelease(keyList);
203
204 pattern = (__bridge_transfer NSString *)SCDynamicStoreKeyCreate(kCFAllocatorDefault,
205 CFSTR("%@/%@/%@/%@/%@"),
206 kSCDynamicStoreDomainSetup,
207 kSCCompNetwork,
208 kSCCompService,
209 kSCCompAnyRegex,
210 kSCCompAnyRegex);
211
212 keyList = SCDynamicStoreCopyKeyList(test.store, (__bridge CFStringRef)pattern);
213 for (int i = 0; i < iterations; i++) {
214 CFDictionaryRef value = SCDynamicStoreCopyMultiple(test.store, keyList, NULL);
215 if (value == NULL) {
216 SCTestLog("Failed to copy multiple values from SCDynamicStore. Error: %s", SCErrorString(SCError()));
217 CFRelease(keyList);
218 return NO;
219 }
220 CFRelease(value);
221 }
222 CFRelease(keyList);
223
224 SCTestLog("Successfully completed copyMultiple unit test");
225 return YES;
226 }
227
228 void
229 myTestCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void *ctx)
230 {
231 SCTestDynamicStore *test = (__bridge SCTestDynamicStore *)ctx;
232 test.counter++;
233 if (test.sem != NULL) {
234 dispatch_semaphore_signal(test.sem);
235 }
236 }
237
238 - (BOOL)unitTestSCDynamicStoreCallbackStress
239 {
240 SCTestDynamicStore *test;
241 int iterations = 100;
242 NSString *testKey = @"State:/myTestKey";
243 BOOL ok;
244 dispatch_queue_t callbackQ;
245
246 test = [[SCTestDynamicStore alloc] initWithOptions:self.options];
247 if (test.store != NULL) {
248 CFRelease(test.store);
249 test.store = NULL;
250 }
251
252 SCDynamicStoreContext ctx = {0, (__bridge void * _Nullable)(test), CFRetain, CFRelease, NULL};
253 test.store = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("SCTest"), myTestCallback, &ctx);
254
255 ok = SCDynamicStoreSetNotificationKeys(test.store, (__bridge CFArrayRef)@[testKey], NULL);
256 if (!ok) {
257 SCTestLog("Failed to set notification keys. Error: %s", SCErrorString(SCError()));
258 return NO;
259 }
260
261 callbackQ = dispatch_queue_create("SCTestDynamicStore callback queue", NULL);
262 ok = SCDynamicStoreSetDispatchQueue(test.store, callbackQ);
263 if (!ok) {
264 SCTestLog("Failed to set dispatch queue. Error: %s", SCErrorString(SCError()));
265 return NO;
266 }
267
268 for (int i = 0; i < iterations; i++) {
269 NSUUID *uuid = [NSUUID UUID];
270 ok = SCDynamicStoreSetValue(test.store, (__bridge CFStringRef)testKey, (__bridge CFStringRef)uuid.UUIDString);
271 if (!ok) {
272 SCTestLog("Failed to set value. Error: %s", SCErrorString(SCError()));
273 return NO;
274 }
275 // Perform a write to Dynamic Store every 10ms.
276 [test waitFor:0.01];
277 }
278
279 ok = SCDynamicStoreRemoveValue(test.store, (__bridge CFStringRef)testKey);
280 if (!ok) {
281 SCTestLog("Failed to remove value. Error: %s", SCErrorString(SCError()));
282 return NO;
283 }
284
285 if (test.counter < iterations) {
286 // Not all callbacks were received
287 SCTestLog("Not all SCDynamicStore callbacks were received (%d/%d). Something went wrong", test.counter, iterations);
288 return NO;
289 }
290
291 SCTestLog("Successfully completed SCDynamicStore callbacks unit test");
292 return YES;
293 }
294
295 - (BOOL)unitTestSCDynamicStoreSetMultipleStress
296 {
297 SCTestDynamicStore *test;
298 int iterations = 100;
299 NSMutableArray *testKeyArray;
300 NSMutableDictionary *testSetDictionary;
301 int expectedCallbackCount = 0;
302 BOOL ok;
303 dispatch_queue_t callbackQ;
304 uint8_t waitTime = 1; // second
305
306 test = [[SCTestDynamicStore alloc] initWithOptions:self.options];
307 if (test.store != NULL) {
308 CFRelease(test.store);
309 test.store = NULL;
310 }
311
312 SCDynamicStoreContext ctx = {0, (__bridge void * _Nullable)(test), CFRetain, CFRelease, NULL};
313 test.store = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("SCTest"), myTestCallback, &ctx);
314 test.sem = dispatch_semaphore_create(0);
315
316 testKeyArray = [[NSMutableArray alloc] init];
317
318 for (int i = 0; i < iterations; i++) {
319 NSUUID *uuid = [NSUUID UUID];
320 NSString *str = [NSString stringWithFormat:@"State:/%@", uuid];
321 [testKeyArray addObject:str];
322 }
323
324 testSetDictionary = [[NSMutableDictionary alloc] init];
325 for (NSString *key in testKeyArray) {
326 NSUUID *uuid = [NSUUID UUID];
327 [testSetDictionary setObject:@[uuid.UUIDString] forKey:key];
328 }
329
330 callbackQ = dispatch_queue_create("SCTestDynamicStore callback queue", NULL);
331 ok = SCDynamicStoreSetNotificationKeys(test.store, (__bridge CFArrayRef)testKeyArray, NULL);
332 if (!ok) {
333 SCTestLog("Failed to set notification keys. Error: %s", SCErrorString(SCError()));
334 return NO;
335 }
336
337 ok = SCDynamicStoreSetDispatchQueue(test.store, callbackQ);
338 if (!ok) {
339 SCTestLog("Failed to set dispatch queue. Error: %s", SCErrorString(SCError()));
340 return NO;
341 }
342
343 ok = SCDynamicStoreSetMultiple(test.store, (__bridge CFDictionaryRef)testSetDictionary, NULL, NULL);
344 if (!ok) {
345 SCTestLog("Failed to set multiple keys. Error: %s", SCErrorString(SCError()));
346 return NO;
347 } else {
348 expectedCallbackCount++; // One callback for set multiple
349 }
350
351 if(dispatch_semaphore_wait(test.sem, dispatch_time(DISPATCH_TIME_NOW, waitTime * NSEC_PER_SEC))) {
352 SCTestLog("Failed to get a callback when multiple keys are set");
353 return NO;
354 }
355
356 ok = SCDynamicStoreSetMultiple(test.store, NULL, NULL, (__bridge CFArrayRef)testKeyArray);
357 if (!ok) {
358 SCTestLog("Failed to set multiple keys. Error: %s", SCErrorString(SCError()));
359 return NO;
360 } else {
361 expectedCallbackCount++; // One callback for fake notification
362 }
363
364 if(dispatch_semaphore_wait(test.sem, dispatch_time(DISPATCH_TIME_NOW, waitTime * NSEC_PER_SEC))) {
365 SCTestLog("Failed to get a callback when multiple keys are notified");
366 return NO;
367 }
368
369 ok = SCDynamicStoreSetMultiple(test.store, NULL, (__bridge CFArrayRef)testKeyArray, NULL);
370 if (!ok) {
371 SCTestLog("Failed to set multiple keys. Error: %s", SCErrorString(SCError()));
372 return NO;
373 } else {
374 expectedCallbackCount++; // One callback for key removal
375 }
376
377 if(dispatch_semaphore_wait(test.sem, dispatch_time(DISPATCH_TIME_NOW, waitTime * NSEC_PER_SEC))) {
378 SCTestLog("Failed to get a callback when multiple keys are removed");
379 return NO;
380 }
381
382 if (test.counter < expectedCallbackCount) {
383 // Not all callbacks were received
384 SCTestLog("Not all SCDynamicStore callbacks were received (%d/%d). Something went wrong", test.counter, expectedCallbackCount);
385 return NO;
386 }
387
388 SCTestLog("Successfully completed SCDynamicStore set multiple unit test");
389 return YES;
390
391 }
392
393
394 @end