2 * Copyright (c) 2016, 2017 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 #import "SCTestUtils.h"
27 @interface SCTestDynamicStore : SCTest
28 @property SCDynamicStoreRef store;
29 @property dispatch_semaphore_t sem;
30 @property int counter;
33 @implementation SCTestDynamicStore
37 return @"dynamic_store";
40 + (NSString *)commandDescription
42 return @"Tests the SCDynamicStore code path";
45 - (instancetype)initWithOptions:(NSDictionary *)options
47 self = [super initWithOptions:options];
49 _store = SCDynamicStoreCreate(kCFAllocatorDefault,
54 SCTestLog("Could not create session");
63 if (self.store != NULL) {
64 CFRelease(self.store);
72 if (self.options[kSCTestDynamicStoreOptionDNS]) {
73 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault, kSCDynamicStoreDomainState, kSCEntNetDNS);
74 CFPropertyListRef value = SCDynamicStoreCopyValue(self.store, key);
75 SCTestLog("%@ : %@", key, value);
82 if (self.options[kSCTestDynamicStoreOptionIPv4]) {
83 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault, kSCDynamicStoreDomainState, kSCEntNetIPv4);
84 CFPropertyListRef value = SCDynamicStoreCopyValue(self.store, key);
85 SCTestLog("%@ : %@", key, value);
92 if (self.options[kSCTestDynamicStoreOptionIPv6]) {
93 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault, kSCDynamicStoreDomainState, kSCEntNetIPv6);
94 CFPropertyListRef value = SCDynamicStoreCopyValue(self.store, key);
95 SCTestLog("%@ : %@", key, value);
102 if (self.options[kSCTestDynamicStoreOptionProxies]) {
103 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault, kSCDynamicStoreDomainState, kSCEntNetProxies);
104 CFPropertyListRef value = SCDynamicStoreCopyValue(self.store, key);
105 SCTestLog("%@ : %@", key, value);
112 [self cleanupAndExitWithErrorCode:0];
115 - (void)cleanupAndExitWithErrorCode:(int)error
117 [super cleanupAndExitWithErrorCode:error];
131 BOOL allUnitTestsPassed = YES;
132 allUnitTestsPassed &= [self unitTestSetAndRemoveValue];
133 allUnitTestsPassed &= [self unitTestCopyMultiple];
134 allUnitTestsPassed &= [self unitTestSCDynamicStoreCallbackStress];
135 allUnitTestsPassed &= [self unitTestSCDynamicStoreSetMultipleStress];
137 if(![self tearDown]) {
141 return allUnitTestsPassed;
149 - (BOOL)unitTestSetAndRemoveValue
151 int iterations = 1000;
152 NSDictionary *bogusValue;
153 SCTestDynamicStore *test;
155 test = [[SCTestDynamicStore alloc] initWithOptions:self.options];
156 bogusValue = @{@"Pretty":@"Useless"};
158 for (int i = 0; i < iterations; i++) {
159 NSUUID *uuid = [NSUUID UUID];
163 key = SCDynamicStoreKeyCreateNetworkServiceEntity(kCFAllocatorDefault,
165 (__bridge CFStringRef)uuid.UUIDString,
167 ok = SCDynamicStoreSetValue(test.store, key, (__bridge CFDictionaryRef)bogusValue);
169 SCTestLog("Failed to set value in SCDynamicStore. Error: %s", SCErrorString(SCError()));
174 ok = SCDynamicStoreRemoveValue(test.store, key);
176 SCTestLog("Failed to remove value from SCDynamicStore. Error: %s", SCErrorString(SCError()));
184 SCTestLog("Successfully completed setAndRemove unit test");
188 - (BOOL)unitTestCopyMultiple
191 SCTestDynamicStore *test;
193 int iterations = 1000;
195 test = [[SCTestDynamicStore alloc] initWithOptions:self.options];
196 pattern = (__bridge_transfer NSString *)SCDynamicStoreKeyCreate(kCFAllocatorDefault,
197 CFSTR("%@/%@/%@/%@/%@"),
198 kSCDynamicStoreDomainState,
204 keyList = SCDynamicStoreCopyKeyList(test.store, (__bridge CFStringRef)pattern);
205 for (int i = 0; i < iterations; i++) {
206 CFDictionaryRef value = SCDynamicStoreCopyMultiple(test.store, keyList, NULL);
208 SCTestLog("Failed to copy multiple values from SCDynamicStore. Error: %s", SCErrorString(SCError()));
216 pattern = (__bridge_transfer NSString *)SCDynamicStoreKeyCreate(kCFAllocatorDefault,
217 CFSTR("%@/%@/%@/%@/%@"),
218 kSCDynamicStoreDomainSetup,
224 keyList = SCDynamicStoreCopyKeyList(test.store, (__bridge CFStringRef)pattern);
225 for (int i = 0; i < iterations; i++) {
226 CFDictionaryRef value = SCDynamicStoreCopyMultiple(test.store, keyList, NULL);
228 SCTestLog("Failed to copy multiple values from SCDynamicStore. Error: %s", SCErrorString(SCError()));
236 SCTestLog("Successfully completed copyMultiple unit test");
241 myTestCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void *ctx)
243 #pragma unused(store)
244 #pragma unused(changedKeys)
245 SCTestDynamicStore *test = (__bridge SCTestDynamicStore *)ctx;
247 if (test.sem != NULL) {
248 dispatch_semaphore_signal(test.sem);
252 - (BOOL)unitTestSCDynamicStoreCallbackStress
254 SCTestDynamicStore *test;
255 int iterations = 100;
256 NSString *testKey = @"State:/myTestKey";
258 dispatch_queue_t callbackQ;
260 test = [[SCTestDynamicStore alloc] initWithOptions:self.options];
261 if (test.store != NULL) {
262 CFRelease(test.store);
266 SCDynamicStoreContext ctx = {0, (__bridge void * _Nullable)(test), CFRetain, CFRelease, NULL};
267 test.store = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("SCTest"), myTestCallback, &ctx);
269 ok = SCDynamicStoreSetNotificationKeys(test.store, (__bridge CFArrayRef)@[testKey], NULL);
271 SCTestLog("Failed to set notification keys. Error: %s", SCErrorString(SCError()));
275 callbackQ = dispatch_queue_create("SCTestDynamicStore callback queue", NULL);
276 ok = SCDynamicStoreSetDispatchQueue(test.store, callbackQ);
278 SCTestLog("Failed to set dispatch queue. Error: %s", SCErrorString(SCError()));
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);
286 SCTestLog("Failed to set value. Error: %s", SCErrorString(SCError()));
289 // Perform a write to Dynamic Store every 10ms.
293 ok = SCDynamicStoreRemoveValue(test.store, (__bridge CFStringRef)testKey);
295 SCTestLog("Failed to remove value. Error: %s", SCErrorString(SCError()));
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);
305 SCTestLog("Successfully completed SCDynamicStore callbacks unit test");
309 - (BOOL)unitTestSCDynamicStoreSetMultipleStress
311 SCTestDynamicStore *test;
312 int iterations = 100;
313 NSMutableArray *testKeyArray;
314 NSMutableDictionary *testSetDictionary;
315 int expectedCallbackCount = 0;
317 dispatch_queue_t callbackQ;
318 uint8_t waitTime = 1; // second
320 test = [[SCTestDynamicStore alloc] initWithOptions:self.options];
321 if (test.store != NULL) {
322 CFRelease(test.store);
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);
330 testKeyArray = [[NSMutableArray alloc] init];
332 for (int i = 0; i < iterations; i++) {
333 NSUUID *uuid = [NSUUID UUID];
334 NSString *str = [NSString stringWithFormat:@"State:/%@", uuid];
335 [testKeyArray addObject:str];
338 testSetDictionary = [[NSMutableDictionary alloc] init];
339 for (NSString *key in testKeyArray) {
340 NSUUID *uuid = [NSUUID UUID];
341 [testSetDictionary setObject:@[uuid.UUIDString] forKey:key];
344 callbackQ = dispatch_queue_create("SCTestDynamicStore callback queue", NULL);
345 ok = SCDynamicStoreSetNotificationKeys(test.store, (__bridge CFArrayRef)testKeyArray, NULL);
347 SCTestLog("Failed to set notification keys. Error: %s", SCErrorString(SCError()));
351 ok = SCDynamicStoreSetDispatchQueue(test.store, callbackQ);
353 SCTestLog("Failed to set dispatch queue. Error: %s", SCErrorString(SCError()));
357 ok = SCDynamicStoreSetMultiple(test.store, (__bridge CFDictionaryRef)testSetDictionary, NULL, NULL);
359 SCTestLog("Failed to set multiple keys. Error: %s", SCErrorString(SCError()));
362 expectedCallbackCount++; // One callback for set multiple
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");
370 ok = SCDynamicStoreSetMultiple(test.store, NULL, NULL, (__bridge CFArrayRef)testKeyArray);
372 SCTestLog("Failed to set multiple keys. Error: %s", SCErrorString(SCError()));
375 expectedCallbackCount++; // One callback for fake notification
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");
383 ok = SCDynamicStoreSetMultiple(test.store, NULL, (__bridge CFArrayRef)testKeyArray, NULL);
385 SCTestLog("Failed to set multiple keys. Error: %s", SCErrorString(SCError()));
388 expectedCallbackCount++; // One callback for key removal
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");
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);
402 SCTestLog("Successfully completed SCDynamicStore set multiple unit test");