2 //  ClientInfoByNotification.m
 
   5 //  Created by murf on 4/12/18.
 
   8 #import <XCTest/XCTest.h>
 
   9 #import <Foundation/Foundation.h>
 
  10 #import <Foundation/NSXPCConnection_Private.h>
 
  11 #import <Security/Security.h>
 
  12 #include <Security/SecureObjectSync/SOSCloudCircle.h>
 
  13 #include <Security/SecureObjectSync/SOSCloudCircleInternal.h>
 
  16 #define DOVIEWMACRO(VIEWNAME, DEFSTRING, CMDSTRING, SYSTEM, DEFAULTSETTING, INITIALSYNCSETTING, ALWAYSONSETTING, BACKUPSETTING, V0SETTING) \
 
  17 const CFStringRef k##SYSTEM##View##VIEWNAME          = CFSTR(DEFSTRING);
 
  18 #include "Security/SecureObjectSync/ViewList.list"
 
  20 #import "DeviceSimulatorProtocol.h"
 
  21 #import "MultiDeviceNetworking.h"
 
  22 #import <objc/runtime.h>
 
  26 @interface MDDevice2 : NSObject<DeviceSimulatorProtocol>
 
  27 @property NSXPCConnection *connection;
 
  28 @property NSString *name;
 
  29 - (instancetype)initWithConnection:(NSXPCConnection *)connection;
 
  32 #pragma clang diagnostic push
 
  33 #pragma clang diagnostic ignored "-Wprotocol"
 
  34 @implementation MDDevice2
 
  36 - (instancetype)initWithConnection:(NSXPCConnection *)connection
 
  40         self.connection = connection;
 
  45 /* Oh, ObjC, you are my friend */
 
  46 - (void)forwardInvocation:(NSInvocation *)invocation
 
  48     struct objc_method_description desc = protocol_getMethodDescription(@protocol(DeviceSimulatorProtocol), [invocation selector], true, true);
 
  49     if (desc.name == NULL) {
 
  50         [super forwardInvocation:invocation];
 
  52         __block bool dooooooEeeeetExclamationPoint = true;
 
  53         id object = [self.connection synchronousRemoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) {
 
  54             NSLog(@"peer failed with: %@", error);
 
  55             dooooooEeeeetExclamationPoint = false;
 
  58         if(dooooooEeeeetExclamationPoint) {
 
  59             [invocation invokeWithTarget:object];
 
  64 #pragma clang diagnostic pop
 
  67 @interface ClientInfoByNotification : XCTestCase
 
  68 @property NSMutableDictionary<NSString *,MDDevice2 *> *connections;
 
  69 @property MultiDeviceNetworking *network;
 
  70 @property MDDevice2 *masterDevice;
 
  73 static NSString *testInstanceUUID;
 
  75 @implementation ClientInfoByNotification
 
  80     testInstanceUUID = [[NSUUID UUID] UUIDString];
 
  85     self.connections = [NSMutableDictionary dictionary];
 
  86     self.network = [[MultiDeviceNetworking alloc] init];
 
  87     [self runSigninWithAdditionalDevices:0];
 
  92     __block uint64_t totalUserUsec = 0, totalSysUsec = 0;
 
  93     NSMutableDictionary *result = [NSMutableDictionary dictionary];
 
  95     for (NSString *name in self.connections) {
 
  96         MDDevice2 *device = self.connections[name];
 
  97         NSLog(@"device: %@", name);
 
  98         [device diagnosticsCPUUsage:^(bool success, uint64_t user_usec, uint64_t sys_usec, NSError *error) {
 
  99             NSLog(@"%@: %d: u:%llu s:%llu", device.name, success, (unsigned long long)user_usec, (unsigned long long)sys_usec);
 
 100             totalUserUsec += user_usec;
 
 101             totalSysUsec += sys_usec;
 
 102             result[[NSString stringWithFormat:@"cpu-%@", name]] = @{ @"user_usec" : @(user_usec), @"system_usec" : @(sys_usec)};
 
 106     result[@"cpu-total"] = @{ @"user_usec" : @(totalUserUsec), @"system_usec" : @(totalSysUsec)};
 
 108     NSLog(@"Total: u:%llu s:%llu", (unsigned long long)totalUserUsec, (unsigned long long)totalSysUsec);
 
 110     /* XXX check for leaks in all devices */
 
 111     for (NSString *name in self.connections) {
 
 112         MDDevice2 *device = self.connections[name];
 
 113         [device.connection invalidate];
 
 115     self.connections = NULL;
 
 116     [self.network dumpKVSState];
 
 117     [self.network dumpCounters];
 
 118     [self.network disconnectAll];
 
 121     NSData * jsonData = [NSJSONSerialization dataWithJSONObject:result options:0 error:NULL];
 
 123     [jsonData writeToFile:[NSString stringWithFormat:@"/tmp/test-result-%@", [self name]] atomically:NO];
 
 127 //MARK: - Device logic
 
 129 - (MDDevice2 *)device:(NSString *)name model:(NSString *)model version:(NSString *)version
 
 131     MDDevice2 *device = self.connections[name];
 
 132     if (device != NULL) {
 
 136     NSXPCConnection *conn = [[NSXPCConnection alloc] initWithServiceName:@"com.apple.Security.DeviceSimulator"];
 
 137     conn.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(DeviceSimulatorProtocol)];
 
 138     [conn _setUUID:[NSUUID UUID]]; // select a random instance
 
 141     device = [[MDDevice2 alloc] initWithConnection:conn];
 
 144     self.connections[name] = device;
 
 146     [device setDevice:name
 
 149          testInstance:testInstanceUUID
 
 150               network:[self.network endpoint]
 
 151              complete:^(BOOL success) {
 
 159 - (void)runSigninWithAdditionalDevices:(unsigned)additionalDeviceCount {
 
 160     signal(SIGPIPE, SIG_IGN);
 
 161     _masterDevice = [self device:@"ipad" model:@"iPad" version:@"15E143a"];
 
 162     NSMutableArray<MDDevice2 *> *otherDevices = [NSMutableArray array];
 
 164     [_masterDevice setupSOSCircle:@"user" password:@"foo" complete:^void(bool success, NSError *error) {
 
 165         XCTAssert(success, "Expect success: %@", error);
 
 168     [_masterDevice sosCircleStatus:^void(SOSCCStatus status, NSError *error) {
 
 169         XCTAssertEqual(status, kSOSCCInCircle, @"expected to be in circle: %@", error);
 
 172     sleep(4); // give "kvs" a chance to get the word out.
 
 173     for (unsigned n = 0; n < additionalDeviceCount; n++) {
 
 174         MDDevice2 *dev = [self device:[NSString stringWithFormat:@"mac-%u", n] model:@"Mac Pro" version:@"17E121"];
 
 176         [dev setupSOSCircle:@"user" password:@"foo" complete:^void(bool success, NSError *error) {
 
 177             XCTAssert(success, "%u: Expect success: %@", n, error);
 
 180         __block NSString *devPeerID = NULL;
 
 181         [dev sosRequestToJoin:^(bool success, NSString *peerID, NSError *error) {
 
 182             XCTAssert(success, "%u: Expect success: %@", n, error);
 
 183             XCTAssertNotEqual(peerID, NULL, @"%u: expected to find peerID for peer2", n);
 
 187         __block NSError *localErr = nil;
 
 188         __block bool done = false;
 
 189         for(int tries=0; tries < 5; tries++) {
 
 191             [_masterDevice sosApprovePeer:devPeerID complete:^(BOOL success, NSError *error) {
 
 192                 localErr = [error copy];
 
 201         XCTAssert(done, "%u: Expect success (for approve of %@): %@", n, devPeerID, localErr);
 
 203         [otherDevices addObject:dev];
 
 207 - (void)testSOSIsThisDeviceInCircle
 
 209     [self measureBlock:^{
 
 210         for(int i=0; i<100; i++) {
 
 211             [self.masterDevice sosCircleStatus:^void(SOSCCStatus status, NSError *error) {
 
 212                 XCTAssertEqual(status, kSOSCCInCircle, @"expected to be in circle: %@", error);
 
 218 - (void)testSOSIsThisDeviceInCircleNonCached
 
 220     [self measureBlock:^{
 
 221         for(int i=0; i<100; i++) {
 
 222             [self.masterDevice sosCircleStatusNonCached:^void(SOSCCStatus status, NSError *error) {
 
 223                 XCTAssertEqual(status, kSOSCCInCircle, @"expected to be in circle: %@", error);
 
 231 - (void)testSOSViews2
 
 233     [self.masterDevice sosViewStatus: (__bridge NSString*)kSOSViewAutofillPasswords withCompletion: ^void(SOSCCStatus status, NSError *error) {
 
 234         XCTAssertEqual(status, kSOSCCViewNotMember, @"expected to be not in view: %@", error);
 
 236     [self.masterDevice sosViewStatus: (__bridge NSString*)kSOSViewHomeKit withCompletion: ^void(SOSCCStatus status, NSError *error) {
 
 237         XCTAssertEqual(status, kSOSCCViewMember, @"expected to be in view: %@", error);
 
 239     [self.masterDevice sosViewStatus: (__bridge NSString*)kSOSViewWiFi withCompletion: ^void(SOSCCStatus status, NSError *error) {
 
 240         XCTAssertEqual(status, kSOSCCViewNotMember, @"expected to be not in view: %@", error);
 
 242     [self.masterDevice sosViewStatus: (__bridge NSString*)kSOSViewContinuityUnlock withCompletion: ^void(SOSCCStatus status, NSError *error) {
 
 243         XCTAssertEqual(status, kSOSCCViewMember, @"expected to be in view: %@", error);
 
 246     [self.masterDevice sosEnableAllViews:^(BOOL success, NSError *error) {
 
 247         XCTAssert(success, "Expected to enable all views");
 
 250     //uint64_t bitmask = [self.masterDevice sosCachedCircleBitmask];
 
 251     //XCTAssertEqual(bitmask, 0, "Expected bitmask to be %llx", bitmask);
 
 254     [self.masterDevice sosViewStatus: (__bridge NSString*)kSOSViewWiFi withCompletion: ^void(SOSCCStatus status, NSError *error) {
 
 255         XCTAssertEqual(status, kSOSCCViewMember, @"expected to be in view: %@", error);
 
 258     [self.masterDevice sosCachedViewBitmask:^(uint64_t bitmask) {
 
 259         XCTAssertEqual(bitmask, 33554367, @"expected bitmask of %llx", bitmask);
 
 262     [self measureBlock:^{
 
 263         for(int i=0; i<100; i++) {
 
 264             [self.masterDevice sosViewStatus: (__bridge NSString*)kSOSViewHomeKit withCompletion: ^void(SOSCCStatus status, NSError *error) {
 
 272 - (void)testSOSMultiView
 
 274     [self.masterDevice sosEnableAllViews:^(BOOL success, NSError *error) {
 
 275         XCTAssert(success, "Expected to enable all views");
 
 278     [self.masterDevice sosICKStatus: ^void(bool status) {
 
 279         XCTAssert(status, "Expected to enable iCloud Keychain");
 
 282     [self measureBlock:^{
 
 283         for(int i=0; i<100; i++) {
 
 284             [self.masterDevice sosICKStatus: ^void(bool status) {
 
 292     [self testSOSMultiView];