]> git.saurik.com Git - apple/configd.git/blob - sctest/SCTestPreferences.m
f4445861b4ee03e02c2d3731717041fd31ca479d
[apple/configd.git] / sctest / SCTestPreferences.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 SCTestPreferences : SCTest
28 @property SCPreferencesRef prefs;
29 @end
30
31 @implementation SCTestPreferences
32
33 + (NSString *)command
34 {
35 return @"preferences";
36 }
37
38 + (NSString *)commandDescription
39 {
40 return @"Tests the SCPreferences code path";
41 }
42
43 - (instancetype)initWithOptions:(NSDictionary *)options
44 {
45 self = [super initWithOptions:options];
46 if (self) {
47 _prefs = SCPreferencesCreate(kCFAllocatorDefault, CFSTR("SCTest"), NULL);
48 }
49 return self;
50 }
51
52 - (void)dealloc
53 {
54 if (self.prefs != NULL) {
55 CFRelease(self.prefs);
56 self.prefs = NULL;
57 }
58 }
59
60 - (void)start
61 {
62 if (self.options[kSCTestPreferencesServiceList]) {
63 NSDictionary *services = (__bridge NSDictionary *)SCPreferencesGetValue(self.prefs, kSCPrefNetworkServices);
64 if (services != nil) {
65 [self printNetworkServicesFromDict:services];
66 } else {
67 SCTestLog("No services present!");
68 }
69 }
70
71 if (self.options[kSCTestPreferencesServiceOrder]) {
72 SCNetworkSetRef set = SCNetworkSetCopyCurrent(self.prefs);
73 NSArray *serviceID = (__bridge NSArray *)SCNetworkSetGetServiceOrder(set);
74 NSDictionary *services = (__bridge NSDictionary *)SCPreferencesGetValue(self.prefs, kSCPrefNetworkServices);
75 int counter = 1;
76 SCTestLog("Network service order");
77 for (NSString *key in serviceID) {
78 NSDictionary *dict = [services objectForKey:key];
79 SCTestLog("\n%d: %@\n\tUserDefinedName: %@", counter++, key, [dict objectForKey:(__bridge NSString *)kSCPropNetServiceUserDefinedName]);
80 }
81 CFRelease(set);
82 }
83
84 [self cleanupAndExitWithErrorCode:0];
85 }
86
87 - (void)printNetworkServicesFromDict:(NSDictionary *)serviceDict
88 {
89 int counter = 1;
90 SCTestLog("Network Services");
91 for (NSString *key in serviceDict) {
92 NSDictionary *dict = [serviceDict objectForKey:key];
93 SCTestLog("\n%d: %@\n\tUserDefinedName: %@", counter++, key, [dict objectForKey:(__bridge NSString *)kSCPropNetServiceUserDefinedName]);
94 }
95 }
96
97 - (BOOL)unitTest
98 {
99 BOOL allUnitTestsPassed = YES;
100 allUnitTestsPassed &= [self unitTestNetworkServicesSanity];
101 allUnitTestsPassed &= [self unitTestPreferencesAPI];
102 allUnitTestsPassed &= [self unitTestPreferencesSession];
103 return allUnitTestsPassed;
104
105 }
106
107 - (BOOL)unitTestNetworkServicesSanity
108 {
109 // We verify that every service has a unique name, an interface, an IPv4 config method and and IPv6 config method.
110 NSDictionary *services;
111 NSMutableArray *serviceNameArray;
112 SCTestPreferences *test;
113
114 test = [[SCTestPreferences alloc] initWithOptions:self.options];
115 services = (__bridge NSDictionary *)SCPreferencesGetValue(test.prefs, kSCPrefNetworkServices);
116 if (services == NULL) {
117 SCTestLog("No services present!");
118 return NO;
119 }
120
121 serviceNameArray = [[NSMutableArray alloc] init];
122 for (NSString *serviceID in services) {
123 NSDictionary *serviceDict;
124 NSString *serviceName;
125 NSDictionary *interfaceDict;
126 NSString *interfaceType;
127 NSDictionary *ipv4Dict;
128 NSDictionary *ipv6Dict;
129
130 serviceDict = [services objectForKey:serviceID];
131 if (![serviceDict isKindOfClass:[NSDictionary class]]) {
132 SCTestLog("Service is not a dictionary");
133 return NO;
134 }
135
136 serviceName = [serviceDict objectForKey:(__bridge NSString *)kSCPropNetServiceUserDefinedName];
137 if (serviceName != nil) {
138 // Check if the name is unique
139 BOOL namePresent = [serviceNameArray containsObject:serviceName];
140 if (!namePresent) {
141 [serviceNameArray addObject:serviceName];
142 } else {
143 SCTestLog("Duplicate services with name %@ exist", serviceName);
144 return NO;
145 }
146 } else {
147 SCTestLog("Service ID %@ does not have a name", serviceID);
148 return NO;
149 }
150
151 interfaceDict = [serviceDict objectForKey:(__bridge NSString *)kSCCompInterface];
152 if (interfaceDict == nil) {
153 SCTestLog("Service %@ does not have an interface", serviceName);
154 return NO;
155 }
156
157 interfaceType = [interfaceDict objectForKey:(__bridge NSString *)kSCPropNetInterfaceType];
158 if (interfaceType != nil && [interfaceType containsString:@"CommCenter"]) {
159 // CommCenter services typically do not have an ipv4/v6 data OR config method. Skip such services.
160 continue;
161 }
162
163 ipv4Dict = [serviceDict objectForKey:(__bridge NSString *)kSCEntNetIPv4];
164 ipv6Dict = [serviceDict objectForKey:(__bridge NSString *)kSCEntNetIPv6];
165
166 // Check that we have at least one IP config method
167 if (ipv4Dict == nil && ipv6Dict == nil) {
168 SCTestLog("Service %@ does not have an IP dictionary", serviceName);
169 return NO;
170 }
171
172 if ([ipv4Dict objectForKey:(__bridge NSString *)kSCPropNetIPv4ConfigMethod] == nil &&
173 [ipv6Dict objectForKey:(__bridge NSString *)kSCPropNetIPv6ConfigMethod] == nil) {
174 SCTestLog("Service %@ does not have an IP Config Method", serviceName);
175 return NO;
176 }
177 }
178
179 SCTestLog("Verified that the Network Services have valid configurations");
180
181 return YES;
182 }
183
184 - (BOOL)unitTestPreferencesSession
185 {
186 SCPreferencesRef prefs;
187 prefs = SCPreferencesCreate(kCFAllocatorDefault, CFSTR("SCTest"), NULL);
188 if (prefs == NULL) {
189 SCTestLog("Failed to create SCPreferences. Error: %s", SCErrorString(SCError()));
190 return NO;
191 } else {
192 CFRelease(prefs);
193 }
194
195 prefs = SCPreferencesCreateWithOptions(kCFAllocatorDefault, CFSTR("SCTest"), NULL, kSCPreferencesUseEntitlementAuthorization, NULL);
196 if (prefs == NULL) {
197 SCTestLog("Failed to create SCPreferences w/options. Error: %s", SCErrorString(SCError()));
198 return NO;
199 } else {
200 CFRelease(prefs);
201 }
202
203 prefs = SCPreferencesCreateWithAuthorization(kCFAllocatorDefault, CFSTR("SCTest"), NULL, kSCPreferencesUseEntitlementAuthorization);
204 if (prefs == NULL) {
205 SCTestLog("Failed to create SCPreferences w/options. Error: %s", SCErrorString(SCError()));
206 return NO;
207 } else {
208 CFRelease(prefs);
209 }
210
211 SCTestLog("Verified that the preferences session can be created");
212 return YES;
213 }
214
215 - (BOOL)unitTestPreferencesAPI
216 {
217 BOOL ok = NO;
218 int iterations = 1000;
219 NSDictionary *prefsOptions;
220 NSMutableArray *keys;
221 NSMutableArray *values;
222 SCTestPreferences *test;
223 NSArray *keyList;
224
225 test = [[SCTestPreferences alloc] initWithOptions:self.options];
226 if (test.prefs != NULL) {
227 CFRelease(test.prefs);
228 test.prefs = NULL;
229 }
230
231 prefsOptions = @{(__bridge NSString *)kSCPreferencesOptionRemoveWhenEmpty:(__bridge NSNumber *)kCFBooleanTrue};
232 test.prefs = SCPreferencesCreateWithOptions(kCFAllocatorDefault,
233 CFSTR("SCTest"),
234 CFSTR("SCTestPreferences.plist"),
235 kSCPreferencesUseEntitlementAuthorization,
236 (__bridge CFDictionaryRef)prefsOptions);
237 if (test.prefs == NULL) {
238 SCTestLog("Failed to create a preferences session. Error: %s", SCErrorString(SCError()));
239 return NO;
240 }
241
242 keys = [[NSMutableArray alloc] init];
243 values = [[NSMutableArray alloc] init];
244 for (int i = 0; i < iterations; i++) {
245 NSUUID *uuidKey = [NSUUID UUID];
246 NSUUID *uuidValue = [NSUUID UUID];
247
248 ok = SCPreferencesLock(test.prefs, true);
249 if (!ok) {
250 SCTestLog("Failed to get preferences lock. Error: %s", SCErrorString(SCError()));
251 return NO;
252 }
253
254 ok = SCPreferencesSetValue(test.prefs, (__bridge CFStringRef)uuidKey.UUIDString, (__bridge CFStringRef)uuidValue.UUIDString);
255 if (!ok) {
256 SCTestLog("Failed to set preferences value. Error: %s", SCErrorString(SCError()));
257 return NO;
258 }
259
260 ok = SCPreferencesUnlock(test.prefs);
261 if (!ok) {
262 SCTestLog("Failed to release preferences lock. Error: %s", SCErrorString(SCError()));
263 return NO;
264 }
265
266 [keys addObject:uuidKey.UUIDString];
267 [values addObject:uuidValue.UUIDString];
268 }
269
270 ok = SCPreferencesCommitChanges(test.prefs);
271 if (!ok) {
272 SCTestLog("Failed to commit preferences. Error: %s", SCErrorString(SCError()));
273 return NO;
274 }
275
276 CFRelease(test.prefs);
277 test.prefs = SCPreferencesCreateWithOptions(kCFAllocatorDefault,
278 CFSTR("SCTest"),
279 CFSTR("SCTestPreferences.plist"),
280 kSCPreferencesUseEntitlementAuthorization,
281 (__bridge CFDictionaryRef)prefsOptions);
282 if (test.prefs == NULL) {
283 SCTestLog("Failed to create a preferences session. Error: %s", SCErrorString(SCError()));
284 return NO;
285 }
286
287 keyList = (__bridge_transfer NSArray *)SCPreferencesCopyKeyList(test.prefs);
288 if ([keyList count] < [keys count]) {
289 SCTestLog("Failed to copy all keys from preferences. Error: %s", SCErrorString(SCError()));
290 return NO;
291 }
292
293 for (NSString *key in keys) {
294 NSString *valueString = (__bridge NSString *)SCPreferencesGetValue(test.prefs, (__bridge CFStringRef)key);
295 if (!valueString) {
296 SCTestLog("Failed to get value from preferences. Error: %s", SCErrorString(SCError()));
297 return NO;
298 }
299
300 BOOL ok = [values containsObject:valueString];
301 if (!ok) {
302 SCTestLog("Incorrect value fetched from preferences");
303 return NO;
304 }
305 }
306
307 ok = SCPreferencesRemoveAllValues(test.prefs);
308 if (!ok) {
309 SCTestLog("Failed to remove values preferences. Error: %s", SCErrorString(SCError()));
310 return NO;
311 }
312
313 ok = SCPreferencesCommitChanges(test.prefs);
314 if (!ok) {
315 SCTestLog("Failed to commit preferences. Error: %s", SCErrorString(SCError()));
316 return NO;
317 }
318
319 CFRelease(test.prefs);
320 test.prefs = SCPreferencesCreateWithOptions(kCFAllocatorDefault,
321 CFSTR("SCTest"),
322 CFSTR("SCTestPreferences.plist"),
323 kSCPreferencesUseEntitlementAuthorization,
324 (__bridge CFDictionaryRef)prefsOptions);
325 if (test.prefs == NULL) {
326 SCTestLog("Failed to create a preferences session. Error: %s", SCErrorString(SCError()));
327 return NO;
328 }
329
330 keyList = (__bridge_transfer NSArray *)SCPreferencesCopyKeyList(test.prefs);
331 if ([keyList count] > 0) {
332 SCTestLog("Failed to remove all keys from preferences. Error: %s", SCErrorString(SCError()));
333 return NO;
334 }
335
336 SCTestLog("Verified that SCPreferences APIs behave as expected");
337 return ok;
338 }
339
340 - (void)cleanupAndExitWithErrorCode:(int)error
341 {
342 [super cleanupAndExitWithErrorCode:error];
343 }
344
345 @end