]> git.saurik.com Git - apple/configd.git/blob - sctest/SCTestDynamicStore.m
configd-963.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 }
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 #pragma unused(store)
232 #pragma unused(changedKeys)
233 SCTestDynamicStore *test = (__bridge SCTestDynamicStore *)ctx;
234 test.counter++;
235 if (test.sem != NULL) {
236 dispatch_semaphore_signal(test.sem);
237 }
238 }
239
240 - (BOOL)unitTestSCDynamicStoreCallbackStress
241 {
242 SCTestDynamicStore *test;
243 int iterations = 100;
244 NSString *testKey = @"State:/myTestKey";
245 BOOL ok;
246 dispatch_queue_t callbackQ;
247
248 test = [[SCTestDynamicStore alloc] initWithOptions:self.options];
249 if (test.store != NULL) {
250 CFRelease(test.store);
251 test.store = NULL;
252 }
253
254 SCDynamicStoreContext ctx = {0, (__bridge void * _Nullable)(test), CFRetain, CFRelease, NULL};
255 test.store = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("SCTest"), myTestCallback, &ctx);
256
257 ok = SCDynamicStoreSetNotificationKeys(test.store, (__bridge CFArrayRef)@[testKey], NULL);
258 if (!ok) {
259 SCTestLog("Failed to set notification keys. Error: %s", SCErrorString(SCError()));
260 return NO;
261 }
262
263 callbackQ = dispatch_queue_create("SCTestDynamicStore callback queue", NULL);
264 ok = SCDynamicStoreSetDispatchQueue(test.store, callbackQ);
265 if (!ok) {
266 SCTestLog("Failed to set dispatch queue. Error: %s", SCErrorString(SCError()));
267 return NO;
268 }
269
270 for (int i = 0; i < iterations; i++) {
271 NSUUID *uuid = [NSUUID UUID];
272 ok = SCDynamicStoreSetValue(test.store, (__bridge CFStringRef)testKey, (__bridge CFStringRef)uuid.UUIDString);
273 if (!ok) {
274 SCTestLog("Failed to set value. Error: %s", SCErrorString(SCError()));
275 return NO;
276 }
277 // Perform a write to Dynamic Store every 10ms.
278 [test waitFor:0.01];
279 }
280
281 ok = SCDynamicStoreRemoveValue(test.store, (__bridge CFStringRef)testKey);
282 if (!ok) {
283 SCTestLog("Failed to remove value. Error: %s", SCErrorString(SCError()));
284 return NO;
285 }
286
287 if (test.counter < iterations) {
288 // Not all callbacks were received
289 SCTestLog("Not all SCDynamicStore callbacks were received (%d/%d). Something went wrong", test.counter, iterations);
290 return NO;
291 }
292
293 SCTestLog("Successfully completed SCDynamicStore callbacks unit test");
294 return YES;
295 }
296
297 - (BOOL)unitTestSCDynamicStoreSetMultipleStress
298 {
299 SCTestDynamicStore *test;
300 int iterations = 100;
301 NSMutableArray *testKeyArray;
302 NSMutableDictionary *testSetDictionary;
303 int expectedCallbackCount = 0;
304 BOOL ok;
305 dispatch_queue_t callbackQ;
306 uint8_t waitTime = 1; // second
307
308 test = [[SCTestDynamicStore alloc] initWithOptions:self.options];
309 if (test.store != NULL) {
310 CFRelease(test.store);
311 test.store = NULL;
312 }
313
314 SCDynamicStoreContext ctx = {0, (__bridge void * _Nullable)(test), CFRetain, CFRelease, NULL};
315 test.store = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("SCTest"), myTestCallback, &ctx);
316 test.sem = dispatch_semaphore_create(0);
317
318 testKeyArray = [[NSMutableArray alloc] init];
319
320 for (int i = 0; i < iterations; i++) {
321 NSUUID *uuid = [NSUUID UUID];
322 NSString *str = [NSString stringWithFormat:@"State:/%@", uuid];
323 [testKeyArray addObject:str];
324 }
325
326 testSetDictionary = [[NSMutableDictionary alloc] init];
327 for (NSString *key in testKeyArray) {
328 NSUUID *uuid = [NSUUID UUID];
329 [testSetDictionary setObject:@[uuid.UUIDString] forKey:key];
330 }
331
332 callbackQ = dispatch_queue_create("SCTestDynamicStore callback queue", NULL);
333 ok = SCDynamicStoreSetNotificationKeys(test.store, (__bridge CFArrayRef)testKeyArray, NULL);
334 if (!ok) {
335 SCTestLog("Failed to set notification keys. Error: %s", SCErrorString(SCError()));
336 return NO;
337 }
338
339 ok = SCDynamicStoreSetDispatchQueue(test.store, callbackQ);
340 if (!ok) {
341 SCTestLog("Failed to set dispatch queue. Error: %s", SCErrorString(SCError()));
342 return NO;
343 }
344
345 ok = SCDynamicStoreSetMultiple(test.store, (__bridge CFDictionaryRef)testSetDictionary, NULL, NULL);
346 if (!ok) {
347 SCTestLog("Failed to set multiple keys. Error: %s", SCErrorString(SCError()));
348 return NO;
349 } else {
350 expectedCallbackCount++; // One callback for set multiple
351 }
352
353 if(dispatch_semaphore_wait(test.sem, dispatch_time(DISPATCH_TIME_NOW, waitTime * NSEC_PER_SEC))) {
354 SCTestLog("Failed to get a callback when multiple keys are set");
355 return NO;
356 }
357
358 ok = SCDynamicStoreSetMultiple(test.store, NULL, NULL, (__bridge CFArrayRef)testKeyArray);
359 if (!ok) {
360 SCTestLog("Failed to set multiple keys. Error: %s", SCErrorString(SCError()));
361 return NO;
362 } else {
363 expectedCallbackCount++; // One callback for fake notification
364 }
365
366 if(dispatch_semaphore_wait(test.sem, dispatch_time(DISPATCH_TIME_NOW, waitTime * NSEC_PER_SEC))) {
367 SCTestLog("Failed to get a callback when multiple keys are notified");
368 return NO;
369 }
370
371 ok = SCDynamicStoreSetMultiple(test.store, NULL, (__bridge CFArrayRef)testKeyArray, NULL);
372 if (!ok) {
373 SCTestLog("Failed to set multiple keys. Error: %s", SCErrorString(SCError()));
374 return NO;
375 } else {
376 expectedCallbackCount++; // One callback for key removal
377 }
378
379 if(dispatch_semaphore_wait(test.sem, dispatch_time(DISPATCH_TIME_NOW, waitTime * NSEC_PER_SEC))) {
380 SCTestLog("Failed to get a callback when multiple keys are removed");
381 return NO;
382 }
383
384 if (test.counter < expectedCallbackCount) {
385 // Not all callbacks were received
386 SCTestLog("Not all SCDynamicStore callbacks were received (%d/%d). Something went wrong", test.counter, expectedCallbackCount);
387 return NO;
388 }
389
390 SCTestLog("Successfully completed SCDynamicStore set multiple unit test");
391 return YES;
392
393 }
394
395
396 @end