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);
79 if (self.options[kSCTestDynamicStoreOptionIPv4]) {
80 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault, kSCDynamicStoreDomainState, kSCEntNetIPv4);
81 CFPropertyListRef value = SCDynamicStoreCopyValue(self.store, key);
82 SCTestLog("%@ : %@", key, value);
86 if (self.options[kSCTestDynamicStoreOptionIPv6]) {
87 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault, kSCDynamicStoreDomainState, kSCEntNetIPv6);
88 CFPropertyListRef value = SCDynamicStoreCopyValue(self.store, key);
89 SCTestLog("%@ : %@", key, value);
93 if (self.options[kSCTestDynamicStoreOptionProxies]) {
94 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault, kSCDynamicStoreDomainState, kSCEntNetProxies);
95 CFPropertyListRef value = SCDynamicStoreCopyValue(self.store, key);
96 SCTestLog("%@ : %@", key, value);
100 [self cleanupAndExitWithErrorCode:0];
103 - (void)cleanupAndExitWithErrorCode:(int)error
105 [super cleanupAndExitWithErrorCode:error];
119 BOOL allUnitTestsPassed = YES;
120 allUnitTestsPassed &= [self unitTestSetAndRemoveValue];
121 allUnitTestsPassed &= [self unitTestCopyMultiple];
122 allUnitTestsPassed &= [self unitTestSCDynamicStoreCallbackStress];
123 allUnitTestsPassed &= [self unitTestSCDynamicStoreSetMultipleStress];
125 if(![self tearDown]) {
129 return allUnitTestsPassed;
137 - (BOOL)unitTestSetAndRemoveValue
139 int iterations = 1000;
140 NSDictionary *bogusValue;
141 SCTestDynamicStore *test;
143 test = [[SCTestDynamicStore alloc] initWithOptions:self.options];
144 bogusValue = @{@"Pretty":@"Useless"};
146 for (int i = 0; i < iterations; i++) {
147 NSUUID *uuid = [NSUUID UUID];
151 key = SCDynamicStoreKeyCreateNetworkServiceEntity(kCFAllocatorDefault,
153 (__bridge CFStringRef)uuid.UUIDString,
155 ok = SCDynamicStoreSetValue(test.store, key, (__bridge CFDictionaryRef)bogusValue);
157 SCTestLog("Failed to set value in SCDynamicStore. Error: %s", SCErrorString(SCError()));
162 ok = SCDynamicStoreRemoveValue(test.store, key);
164 SCTestLog("Failed to remove value from SCDynamicStore. Error: %s", SCErrorString(SCError()));
172 SCTestLog("Successfully completed setAndRemove unit test");
176 - (BOOL)unitTestCopyMultiple
179 SCTestDynamicStore *test;
181 int iterations = 1000;
183 test = [[SCTestDynamicStore alloc] initWithOptions:self.options];
184 pattern = (__bridge_transfer NSString *)SCDynamicStoreKeyCreate(kCFAllocatorDefault,
185 CFSTR("%@/%@/%@/%@/%@"),
186 kSCDynamicStoreDomainState,
192 keyList = SCDynamicStoreCopyKeyList(test.store, (__bridge CFStringRef)pattern);
193 for (int i = 0; i < iterations; i++) {
194 CFDictionaryRef value = SCDynamicStoreCopyMultiple(test.store, keyList, NULL);
196 SCTestLog("Failed to copy multiple values from SCDynamicStore. Error: %s", SCErrorString(SCError()));
204 pattern = (__bridge_transfer NSString *)SCDynamicStoreKeyCreate(kCFAllocatorDefault,
205 CFSTR("%@/%@/%@/%@/%@"),
206 kSCDynamicStoreDomainSetup,
212 keyList = SCDynamicStoreCopyKeyList(test.store, (__bridge CFStringRef)pattern);
213 for (int i = 0; i < iterations; i++) {
214 CFDictionaryRef value = SCDynamicStoreCopyMultiple(test.store, keyList, NULL);
216 SCTestLog("Failed to copy multiple values from SCDynamicStore. Error: %s", SCErrorString(SCError()));
224 SCTestLog("Successfully completed copyMultiple unit test");
229 myTestCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void *ctx)
231 #pragma unused(store)
232 #pragma unused(changedKeys)
233 SCTestDynamicStore *test = (__bridge SCTestDynamicStore *)ctx;
235 if (test.sem != NULL) {
236 dispatch_semaphore_signal(test.sem);
240 - (BOOL)unitTestSCDynamicStoreCallbackStress
242 SCTestDynamicStore *test;
243 int iterations = 100;
244 NSString *testKey = @"State:/myTestKey";
246 dispatch_queue_t callbackQ;
248 test = [[SCTestDynamicStore alloc] initWithOptions:self.options];
249 if (test.store != NULL) {
250 CFRelease(test.store);
254 SCDynamicStoreContext ctx = {0, (__bridge void * _Nullable)(test), CFRetain, CFRelease, NULL};
255 test.store = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("SCTest"), myTestCallback, &ctx);
257 ok = SCDynamicStoreSetNotificationKeys(test.store, (__bridge CFArrayRef)@[testKey], NULL);
259 SCTestLog("Failed to set notification keys. Error: %s", SCErrorString(SCError()));
263 callbackQ = dispatch_queue_create("SCTestDynamicStore callback queue", NULL);
264 ok = SCDynamicStoreSetDispatchQueue(test.store, callbackQ);
266 SCTestLog("Failed to set dispatch queue. Error: %s", SCErrorString(SCError()));
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);
274 SCTestLog("Failed to set value. Error: %s", SCErrorString(SCError()));
277 // Perform a write to Dynamic Store every 10ms.
281 ok = SCDynamicStoreRemoveValue(test.store, (__bridge CFStringRef)testKey);
283 SCTestLog("Failed to remove value. Error: %s", SCErrorString(SCError()));
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);
293 SCTestLog("Successfully completed SCDynamicStore callbacks unit test");
297 - (BOOL)unitTestSCDynamicStoreSetMultipleStress
299 SCTestDynamicStore *test;
300 int iterations = 100;
301 NSMutableArray *testKeyArray;
302 NSMutableDictionary *testSetDictionary;
303 int expectedCallbackCount = 0;
305 dispatch_queue_t callbackQ;
306 uint8_t waitTime = 1; // second
308 test = [[SCTestDynamicStore alloc] initWithOptions:self.options];
309 if (test.store != NULL) {
310 CFRelease(test.store);
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);
318 testKeyArray = [[NSMutableArray alloc] init];
320 for (int i = 0; i < iterations; i++) {
321 NSUUID *uuid = [NSUUID UUID];
322 NSString *str = [NSString stringWithFormat:@"State:/%@", uuid];
323 [testKeyArray addObject:str];
326 testSetDictionary = [[NSMutableDictionary alloc] init];
327 for (NSString *key in testKeyArray) {
328 NSUUID *uuid = [NSUUID UUID];
329 [testSetDictionary setObject:@[uuid.UUIDString] forKey:key];
332 callbackQ = dispatch_queue_create("SCTestDynamicStore callback queue", NULL);
333 ok = SCDynamicStoreSetNotificationKeys(test.store, (__bridge CFArrayRef)testKeyArray, NULL);
335 SCTestLog("Failed to set notification keys. Error: %s", SCErrorString(SCError()));
339 ok = SCDynamicStoreSetDispatchQueue(test.store, callbackQ);
341 SCTestLog("Failed to set dispatch queue. Error: %s", SCErrorString(SCError()));
345 ok = SCDynamicStoreSetMultiple(test.store, (__bridge CFDictionaryRef)testSetDictionary, NULL, NULL);
347 SCTestLog("Failed to set multiple keys. Error: %s", SCErrorString(SCError()));
350 expectedCallbackCount++; // One callback for set multiple
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");
358 ok = SCDynamicStoreSetMultiple(test.store, NULL, NULL, (__bridge CFArrayRef)testKeyArray);
360 SCTestLog("Failed to set multiple keys. Error: %s", SCErrorString(SCError()));
363 expectedCallbackCount++; // One callback for fake notification
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");
371 ok = SCDynamicStoreSetMultiple(test.store, NULL, (__bridge CFArrayRef)testKeyArray, NULL);
373 SCTestLog("Failed to set multiple keys. Error: %s", SCErrorString(SCError()));
376 expectedCallbackCount++; // One callback for key removal
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");
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);
390 SCTestLog("Successfully completed SCDynamicStore set multiple unit test");