diff --git a/.github/workflows/darwin.yaml b/.github/workflows/darwin.yaml index c30cc044f35b33..1eddaec04a8667 100644 --- a/.github/workflows/darwin.yaml +++ b/.github/workflows/darwin.yaml @@ -95,15 +95,9 @@ jobs: - name: Build example OTA Provider run: | scripts/examples/gn_build_example.sh examples/ota-provider-app/linux out/debug chip_config_network_layer_ble=false - - name: Build OTA image files with software version number 5 and 10 - run: | - scripts/examples/gn_build_example.sh examples/ota-requestor-app/linux out/debug chip_config_network_layer_ble=false non_spec_compliant_ota_action_delay_floor=0 chip_device_config_device_software_version=5 chip_device_config_device_software_version_string='"5.0"' - cp out/debug/chip-ota-requestor-app /tmp/ota-raw-image-v5 - scripts/examples/gn_build_example.sh examples/ota-requestor-app/linux out/debug chip_config_network_layer_ble=false non_spec_compliant_ota_action_delay_floor=0 chip_device_config_device_software_version=10 chip_device_config_device_software_version_string='"10.0"' - cp out/debug/chip-ota-requestor-app /tmp/ota-raw-image-v10 - name: Build example OTA Requestor run: | - scripts/examples/gn_build_example.sh examples/ota-requestor-app/linux out/debug chip_config_network_layer_ble=false non_spec_compliant_ota_action_delay_floor=0 + scripts/examples/gn_build_example.sh examples/ota-requestor-app/linux out/debug/ota-requestor-app chip_config_network_layer_ble=false non_spec_compliant_ota_action_delay_floor=0 - name: Delete Defaults run: defaults delete com.apple.dt.xctest.tool continue-on-error: true @@ -116,13 +110,6 @@ jobs: mkdir -p /tmp/darwin/framework-tests ../../../out/debug/chip-all-clusters-app --interface-id -1 > >(tee /tmp/darwin/framework-tests/all-cluster-app.log) 2> >(tee /tmp/darwin/framework-tests/all-cluster-app-err.log >&2) & ../../../out/debug/chip-all-clusters-app --interface-id -1 --dac_provider ../../../credentials/development/commissioner_dut/struct_cd_origin_pid_vid_correct/test_case_vector.json --product-id 32768 --discriminator 3839 --secured-device-port 5539 --KVS /tmp/chip-all-clusters-app-kvs2 > >(tee /tmp/darwin/framework-tests/all-cluster-app-origin-vid.log) 2> >(tee /tmp/darwin/framework-tests/all-cluster-app-origin-vid-err.log >&2) & - # Make sure each ota-requestor is using a different port, discriminator, and KVS from - # all-clusters-app and from other requestors. - # - # And a different port from the test harness too; the test harness uses port 5541. - ../../../out/debug/chip-ota-requestor-app --interface-id -1 --secured-device-port 5542 --discriminator 1111 --KVS /tmp/chip-ota-requestor-kvs1 --otaDownloadPath /tmp/chip-ota-requestor-downloaded-image1 --autoApplyImage > >(tee /tmp/darwin/framework-tests/ota-requestor-app-1.log) 2> >(tee /tmp/darwin/framework-tests/ota-requestor-app-err-1.log >&2) & - ../../../out/debug/chip-ota-requestor-app --interface-id -1 --secured-device-port 5543 --discriminator 1112 --KVS /tmp/chip-ota-requestor-kvs2 --otaDownloadPath /tmp/chip-ota-requestor-downloaded-image2 --autoApplyImage > >(tee /tmp/darwin/framework-tests/ota-requestor-app-2.log) 2> >(tee /tmp/darwin/framework-tests/ota-requestor-app-err-2.log >&2) & - ../../../out/debug/chip-ota-requestor-app --interface-id -1 --secured-device-port 5544 --discriminator 1113 --KVS /tmp/chip-ota-requestor-kvs3 --otaDownloadPath /tmp/chip-ota-requestor-downloaded-image3 --autoApplyImage > >(tee /tmp/darwin/framework-tests/ota-requestor-app-3.log) 2> >(tee /tmp/darwin/framework-tests/ota-requestor-app-err-3.log >&2) & # Disable BLE because the app does not have the permission to use # it and that may crash the CI. # diff --git a/src/darwin/Framework/CHIP/MTROTAProviderDelegateBridge.mm b/src/darwin/Framework/CHIP/MTROTAProviderDelegateBridge.mm index d64522f4ceded7..4ebef0535253ee 100644 --- a/src/darwin/Framework/CHIP/MTROTAProviderDelegateBridge.mm +++ b/src/darwin/Framework/CHIP/MTROTAProviderDelegateBridge.mm @@ -108,7 +108,6 @@ CHIP_ERROR Shutdown() mExchangeMgr = nullptr; mSystemLayer = nullptr; - mDelegateNotificationQueue = nil; return CHIP_NO_ERROR; } diff --git a/src/darwin/Framework/CHIPTests/MTRCommissionableBrowserTests.m b/src/darwin/Framework/CHIPTests/MTRCommissionableBrowserTests.m index c984ac670a8500..8c9eb603d08518 100644 --- a/src/darwin/Framework/CHIPTests/MTRCommissionableBrowserTests.m +++ b/src/darwin/Framework/CHIPTests/MTRCommissionableBrowserTests.m @@ -27,13 +27,10 @@ static const uint16_t kTestVendorId = 0xFFF1u; static const uint16_t kTestProductId1 = 0x8000u; static const uint16_t kTestProductId2 = 0x8001u; -static const uint16_t kTestDiscriminator1 = 1111u; -static const uint16_t kTestDiscriminator2 = 1112u; -static const uint16_t kTestDiscriminator3 = 1113u; -static const uint16_t kTestDiscriminator4 = 3840u; -static const uint16_t kTestDiscriminator5 = 3839u; +static const uint16_t kTestDiscriminator1 = 3840u; +static const uint16_t kTestDiscriminator2 = 3839u; static const uint16_t kDiscoverDeviceTimeoutInSeconds = 10; -static const uint16_t kExpectedDiscoveredDevicesCount = 5; +static const uint16_t kExpectedDiscoveredDevicesCount = 2; // Singleton controller we use. static MTRDeviceController * sController = nil; @@ -77,9 +74,7 @@ - (void)controller:(MTRDeviceController *)controller didFindCommissionableDevice XCTAssertEqual(instanceName.length, 16); // The instance name is random, so just ensure the len is right. XCTAssertEqualObjects(vendorId, @(kTestVendorId)); XCTAssertTrue([productId isEqual:@(kTestProductId1)] || [productId isEqual:@(kTestProductId2)]); - XCTAssertTrue([discriminator isEqual:@(kTestDiscriminator1)] || [discriminator isEqual:@(kTestDiscriminator2)] || - [discriminator isEqual:@(kTestDiscriminator3)] || [discriminator isEqual:@(kTestDiscriminator4)] || - [discriminator isEqual:@(kTestDiscriminator5)]); + XCTAssertTrue([discriminator isEqual:@(kTestDiscriminator1)] || [discriminator isEqual:@(kTestDiscriminator2)]); XCTAssertEqual(commissioningMode, YES); NSLog(@"Found Device (%@) with discriminator: %@ (vendor: %@, product: %@)", instanceName, discriminator, vendorId, productId); diff --git a/src/darwin/Framework/CHIPTests/MTROTAProviderTests.m b/src/darwin/Framework/CHIPTests/MTROTAProviderTests.m index 472bd22d9919c7..c464e325ca436d 100644 --- a/src/darwin/Framework/CHIPTests/MTROTAProviderTests.m +++ b/src/darwin/Framework/CHIPTests/MTROTAProviderTests.m @@ -46,32 +46,22 @@ static const uint16_t kTimeoutWithUpdateInSeconds = 60; static const uint64_t kDeviceId1 = 0x12341234; static const uint64_t kDeviceId2 = 0x12341235; +#ifdef ENABLE_REAL_OTA_UPDATE_TESTS static const uint64_t kDeviceId3 = 0x12341236; +#endif // ENABLE_REAL_OTA_UPDATE_TESTS // NOTE: These onboarding payloads are for the chip-ota-requestor-app, not chip-all-clusters-app static NSString * kOnboardingPayload1 = @"MT:-24J0SO527K10648G00"; // Discriminator: 1111 static NSString * kOnboardingPayload2 = @"MT:-24J0AFN00L10648G00"; // Discriminator: 1112 +#ifdef ENABLE_REAL_OTA_UPDATE_TESTS static NSString * kOnboardingPayload3 = @"MT:-24J0IRV01L10648G00"; // Discriminator: 1113 +#endif // ENABLE_REAL_OTA_UPDATE_TESTS static const uint16_t kLocalPort = 5541; static const uint16_t kTestVendorId = 0xFFF1u; static const uint16_t kOTAProviderEndpointId = 0; -static MTRDevice * sConnectedDevice1; -static MTRDevice * sConnectedDevice2; -static MTRDevice * sConnectedDevice3; - -// Singleton controller we use. static MTRDeviceController * sController = nil; -// Keys we can use to restart the controller. -static MTRTestKeys * sTestKeys = nil; - -static NSString * kOtaDownloadedFilePath1 = @"/tmp/chip-ota-requestor-downloaded-image1"; - -static NSString * kOtaDownloadedFilePath2 = @"/tmp/chip-ota-requestor-downloaded-image2"; - -static NSString * kOtaDownloadedFilePath3 = @"/tmp/chip-ota-requestor-downloaded-image3"; - static NSNumber * kUpdatedSoftwareVersion_5 = @5; static NSString * kUpdatedSoftwareVersionString_5 = @"5.0"; @@ -80,6 +70,111 @@ static NSString * kUpdatedSoftwareVersionString_10 = @"10.0"; +// kOtaRequestorBasePort gets the discriminator added to it to figure out the +// port the ota-requestor app should be using. This ensures that apps with +// distinct discriminators use distinct ports. +static const uint16_t kOtaRequestorBasePort = 5542 - 1111; + +@class MTROTARequestorAppRunner; + +@interface MTROTAProviderTests : XCTestCase +#if ENABLE_OTA_TESTS +- (NSTask *)createTaskForPath:(NSString *)path; +- (NSString *)createImageFromRawImage:(NSString *)rawImage withVersion:(NSNumber *)version; +- (MTRDevice *)commissionDeviceWithPayload:(NSString *)payloadString nodeID:(NSNumber *)nodeID; +- (void)registerRunningRequestor:(MTROTARequestorAppRunner *)requestor; +#endif // ENABLE_OTA_TESTS +@end + +#if ENABLE_OTA_TESTS +static unsigned sAppRunnerIndex = 1; + +@interface MTROTARequestorAppRunner : NSObject +@property (nonatomic, copy) NSString * downloadFilePath; + +- (instancetype)initWithPayload:(NSString *)payload testcase:(MTROTAProviderTests *)testcase; +- (MTRDevice *)commissionWithNodeID:(NSNumber *)nodeID; +@end + +@implementation MTROTARequestorAppRunner { + unsigned _uniqueIndex; + NSTask * _appTask; + MTROTAProviderTests * _testcase; + NSString * _payload; + MTRDevice * commissionedDevice; +} + +- (MTRDevice *)commissionWithNodeID:(NSNumber *)nodeID +{ + return [_testcase commissionDeviceWithPayload:_payload nodeID:nodeID]; +} + +- (instancetype)initWithPayload:(NSString *)payload testcase:(MTROTAProviderTests *)testcase +{ + if (!(self = [super init])) { + return nil; + } + + _uniqueIndex = sAppRunnerIndex++; + _testcase = testcase; + _payload = payload; + _downloadFilePath = [NSString stringWithFormat:@"/tmp/chip-ota-requestor-downloaded-image%u", _uniqueIndex]; + + NSError * error; + __auto_type * parsedPayload = [MTRSetupPayload setupPayloadWithOnboardingPayload:payload error:&error]; + XCTAssertNotNil(parsedPayload); + XCTAssertNil(error); + + XCTAssertFalse(parsedPayload.hasShortDiscriminator); + + __auto_type * discriminator = parsedPayload.discriminator; + + _appTask = [testcase createTaskForPath:@"out/debug/ota-requestor-app/chip-ota-requestor-app"]; + + __auto_type * arguments = @[ + @"--interface-id", + @"-1", + @"--secured-device-port", + [NSString stringWithFormat:@"%u", kOtaRequestorBasePort + discriminator.unsignedShortValue], + @"--discriminator", + [NSString stringWithFormat:@"%u", discriminator.unsignedShortValue], + @"--KVS", + [NSString stringWithFormat:@"/tmp/chip-ota-requestor-kvs%u", _uniqueIndex], + @"--otaDownloadPath", + _downloadFilePath, + @"--autoApplyImage", + ]; + + [_appTask setArguments:arguments]; + + NSString * outFile = [NSString stringWithFormat:@"/tmp/darwin/framework-tests/ota-requestor-app-%u.log", _uniqueIndex]; + NSString * errorFile = [NSString stringWithFormat:@"/tmp/darwin/framework-tests/ota-requestor-app-err-%u.log", _uniqueIndex]; + + // Make sure the files exist. + [[NSFileManager defaultManager] createFileAtPath:outFile contents:nil attributes:nil]; + [[NSFileManager defaultManager] createFileAtPath:errorFile contents:nil attributes:nil]; + + _appTask.standardOutput = [NSFileHandle fileHandleForWritingAtPath:outFile]; + _appTask.standardError = [NSFileHandle fileHandleForWritingAtPath:errorFile]; + + [_appTask launchAndReturnError:&error]; + XCTAssertNil(error); + + NSLog(@"Started requestor with arguments %@ stdout=%@ and stderr=%@", arguments, outFile, errorFile); + + [_testcase registerRunningRequestor:self]; + + return self; +} + +- (void)terminate +{ + [_appTask terminate]; +} + +@end +#endif // ENABLE_OTA_TESTS + @interface MTROTAProviderTestControllerDelegate : NSObject @property (nonatomic, readonly) XCTestExpectation * expectation; @property (nonatomic, readonly) NSNumber * commissioneeNodeID; @@ -352,7 +447,7 @@ - (instancetype)initWithRawImagePath:(NSString *)rawImagePath softwareVersion:(NSNumber *)softwareVersion softwareVersionString:(NSString *)softwareVersionString applyUpdateAction:(MTROTASoftwareUpdateProviderOTAApplyUpdateAction)applyUpdateAction - testcase:(XCTestCase *)testcase + testcase:(MTROTAProviderTests *)testcase { if (!(self = [super init])) { return nil; @@ -365,28 +460,7 @@ - (instancetype)initWithRawImagePath:(NSString *)rawImagePath _applyUpdateRequestExpectation = [testcase expectationWithDescription:@"handleApplyUpdateRequestForNodeID called"]; _notifyUpdateAppliedExpectation = [testcase expectationWithDescription:@"handleNotifyUpdateAppliedForNodeID called"]; - NSString * imagePath = [rawImagePath stringByReplacingOccurrencesOfString:@"raw-image" withString:@"image"]; - - // Find the right absolute path to our ota_image_tool.py script. PWD should - // point to our src/darwin/Framework, while the script is in - // src/app/ota_image_tool.py. - NSString * pwd = [[NSProcessInfo processInfo] environment][@"PWD"]; - NSString * imageToolPath = [NSString - pathWithComponents:@[ [pwd substringToIndex:(pwd.length - @"darwin/Framework".length)], @"app", @"ota_image_tool.py" ]]; - -#if ENABLE_OTA_TESTS - NSTask * task = [[NSTask alloc] init]; - [task setLaunchPath:imageToolPath]; - [task setArguments:@[ - @"create", @"-v", @"0xFFF1", @"-p", @"0x8001", @"-vn", [softwareVersion stringValue], @"-vs", softwareVersionString, @"-da", - @"sha256", rawImagePath, imagePath - ]]; - NSError * launchError = nil; - [task launchAndReturnError:&launchError]; - XCTAssertNil(launchError); - [task waitUntilExit]; - XCTAssertEqual([task terminationStatus], 0); -#endif + NSString * imagePath = [testcase createImageFromRawImage:rawImagePath withVersion:softwareVersion]; NSData * updateToken = [sOTAProviderDelegate generateUpdateToken]; @@ -501,13 +575,15 @@ - (instancetype)initWithRawImagePath:(NSString *)rawImagePath } @end -@interface MTROTAProviderTests : XCTestCase -@end - static BOOL sStackInitRan = NO; static BOOL sNeedsStackShutdown = YES; -@implementation MTROTAProviderTests +@implementation MTROTAProviderTests { + NSMutableSet * _commissionedNodeIDs; + NSMutableSet * _runningRequestors; +} + +#if ENABLE_OTA_TESTS + (void)tearDown { @@ -531,16 +607,51 @@ - (void)setUp [self initStack]; } + _commissionedNodeIDs = [[NSMutableSet alloc] init]; + _runningRequestors = [[NSMutableSet alloc] init]; + XCTAssertNil(sOTAProviderDelegate.queryImageHandler); XCTAssertNil(sOTAProviderDelegate.applyUpdateRequestHandler); XCTAssertNil(sOTAProviderDelegate.notifyUpdateAppliedHandler); XCTAssertNil(sOTAProviderDelegate.transferBeginHandler); XCTAssertNil(sOTAProviderDelegate.blockQueryHandler); XCTAssertNil(sOTAProviderDelegate.transferEndHandler); + + // Start a new controller for each test, with a new fabric. Otherwise + // reusing the same node id for our commissionee devices will cause us to + // try to reuse sessions in ways that fail. + __auto_type * testKeys = [[MTRTestKeys alloc] init]; + XCTAssertNotNil(testKeys); + + __auto_type * params = [[MTRDeviceControllerStartupParams alloc] initWithIPK:testKeys.ipk fabricID:@(1) nocSigner:testKeys]; + params.vendorID = @(kTestVendorId); + + MTRDeviceController * controller = [[MTRDeviceControllerFactory sharedInstance] createControllerOnNewFabric:params error:nil]; + XCTAssertNotNil(controller); + XCTAssertTrue([controller isRunning]); + + sController = controller; } - (void)tearDown { + for (NSNumber * nodeID in _commissionedNodeIDs) { + __auto_type * device = [MTRBaseDevice deviceWithNodeID:nodeID controller:sController]; + ResetCommissionee(device, dispatch_get_main_queue(), self, kTimeoutInSeconds); + } + + for (MTROTARequestorAppRunner * runner in _runningRequestors) { + [runner terminate]; + } + // Break cycle. + _runningRequestors = nil; + + if (sController != nil) { + [sController shutdown]; + XCTAssertFalse([sController isRunning]); + sController = nil; + } + // Per-test teardown, runs after each test. [super tearDown]; @@ -573,9 +684,16 @@ - (MTRDevice *)commissionDeviceWithPayload:(NSString *)payloadString nodeID:(NSN [self waitForExpectations:@[ expectation ] timeout:kPairingTimeoutInSeconds]; + [_commissionedNodeIDs addObject:nodeID]; + return [MTRDevice deviceWithNodeID:nodeID controller:sController]; } +- (void)registerRunningRequestor:(MTROTARequestorAppRunner *)requestor +{ + [_runningRequestors addObject:requestor]; +} + - (void)initStack { sStackInitRan = YES; @@ -593,41 +711,103 @@ - (void)initStack BOOL ok = [factory startControllerFactory:factoryParams error:nil]; XCTAssertTrue(ok); +} - __auto_type * testKeys = [[MTRTestKeys alloc] init]; - XCTAssertNotNil(testKeys); ++ (void)shutdownStack +{ + sNeedsStackShutdown = NO; - sTestKeys = testKeys; + [[MTRDeviceControllerFactory sharedInstance] stopControllerFactory]; +} - // Needs to match what startControllerOnExistingFabric calls elsewhere in - // this file do. - __auto_type * params = [[MTRDeviceControllerStartupParams alloc] initWithIPK:testKeys.ipk fabricID:@(1) nocSigner:testKeys]; - params.vendorID = @(kTestVendorId); +/** + * Given a path relative to the Matter root, create an absolute path to the file. + */ +- (NSString *)absolutePathFor:(NSString *)matterRootRelativePath +{ + // Find the right absolute path to our file. PWD should + // point to our src/darwin/Framework. + NSString * pwd = [[NSProcessInfo processInfo] environment][@"PWD"]; + NSMutableArray * pathComponents = [[NSMutableArray alloc] init]; + [pathComponents addObject:[pwd substringToIndex:(pwd.length - @"src/darwin/Framework".length)]]; + [pathComponents addObjectsFromArray:[matterRootRelativePath pathComponents]]; + return [NSString pathWithComponents:pathComponents]; +} - MTRDeviceController * controller = [factory createControllerOnNewFabric:params error:nil]; - XCTAssertNotNil(controller); +/** + * Create a task given a path relative to the Matter root. + */ +- (NSTask *)createTaskForPath:(NSString *)path +{ + NSTask * task = [[NSTask alloc] init]; + [task setLaunchPath:[self absolutePathFor:path]]; + return task; +} - sController = controller; +/** + * Runs a task to completion and makes sure it succeeds. + */ +- (void)runTask:(NSTask *)task +{ + NSError * launchError; + [task launchAndReturnError:&launchError]; + XCTAssertNil(launchError); - sConnectedDevice1 = [self commissionDeviceWithPayload:kOnboardingPayload1 nodeID:@(kDeviceId1)]; - sConnectedDevice2 = [self commissionDeviceWithPayload:kOnboardingPayload2 nodeID:@(kDeviceId2)]; - sConnectedDevice3 = [self commissionDeviceWithPayload:kOnboardingPayload3 nodeID:@(kDeviceId3)]; + [task waitUntilExit]; + XCTAssertEqual([task terminationStatus], 0); } -+ (void)shutdownStack +/** + * Returns path to the raw image. + */ +- (NSString *)createRawImageWithVersion:(NSNumber *)version { - sNeedsStackShutdown = NO; + NSTask * buildTask = [self createTaskForPath:@"scripts/examples/gn_build_example.sh"]; + NSString * objdir = + [self absolutePathFor:[NSString stringWithFormat:@"out/debug/ota-requestor-app-v%u", version.unsignedIntValue]]; + [buildTask setArguments:@[ + [self absolutePathFor:@"examples/ota-requestor-app/linux"], + objdir, + @"chip_config_network_layer_ble=false", + @"non_spec_compliant_ota_action_delay_floor=0", + [NSString stringWithFormat:@"chip_device_config_device_software_version=%u", version.unsignedIntValue], + [NSString stringWithFormat:@"chip_device_config_device_software_version_string=\"%u.0\"", version.unsignedIntValue], + ]]; - MTRDeviceController * controller = sController; - XCTAssertNotNil(controller); + [self runTask:buildTask]; - [controller shutdown]; - XCTAssertFalse([controller isRunning]); + NSString * sourcePath = [NSString pathWithComponents:@[ objdir, @"chip-ota-requestor-app" ]]; + NSString * destPath = [NSString stringWithFormat:@"/tmp/ota-raw-image-v%u", version.unsignedIntValue]; - [[MTRDeviceControllerFactory sharedInstance] stopControllerFactory]; + // We don't care about error on remove; the file might not be there. But if + // it _is_ there, we have to remove, or the copy will fail. + [[NSFileManager defaultManager] removeItemAtPath:destPath error:nil]; + + NSError * copyError; + BOOL ok = [[NSFileManager defaultManager] copyItemAtPath:sourcePath toPath:destPath error:©Error]; + XCTAssertNil(copyError); + XCTAssertTrue(ok); + + return destPath; } -#if ENABLE_OTA_TESTS +/** + * Returns path to the created image. + */ +- (NSString *)createImageFromRawImage:(NSString *)rawImage withVersion:(NSNumber *)version +{ + NSString * image = [rawImage stringByReplacingOccurrencesOfString:@"raw-image" withString:@"image"]; + + NSTask * task = [self createTaskForPath:@"src/app/ota_image_tool.py"]; + [task setArguments:@[ + @"create", @"-v", @"0xFFF1", @"-p", @"0x8001", @"-vn", version.stringValue, @"-vs", + [NSString stringWithFormat:@"%.1f", version.floatValue], @"-da", @"sha256", rawImage, image + ]]; + + [self runTask:task]; + + return image; +} - (void)test000_SetUp { @@ -665,7 +845,8 @@ - (void)test001_ReceiveQueryImageRequest_RespondUpdateNotAvailable { // Test that if we advertise ourselves as a provider we end up getting a // QueryImage callbacks that we can respond to. - __auto_type * device = sConnectedDevice1; + __auto_type * runner = [[MTROTARequestorAppRunner alloc] initWithPayload:kOnboardingPayload1 testcase:self]; + __auto_type * device = [runner commissionWithNodeID:@(kDeviceId1)]; XCTestExpectation * queryExpectation = [self expectationWithDescription:@"handleQueryImageForNodeID called"]; sOTAProviderDelegate.queryImageHandler = ^(NSNumber * nodeID, MTRDeviceController * controller, @@ -689,7 +870,8 @@ - (void)test002_ReceiveTwoQueryImageRequests_RespondExplicitBusy // Test that if we advertise ourselves as a provider and respond BUSY to // QueryImage callback, then we get a second QueryImage callback later on // that we can then respond to however we wish. - __auto_type * device = sConnectedDevice1; + __auto_type * runner = [[MTROTARequestorAppRunner alloc] initWithPayload:kOnboardingPayload1 testcase:self]; + __auto_type * device = [runner commissionWithNodeID:@(kDeviceId1)]; XCTestExpectation * queryExpectation1 = [self expectationWithDescription:@"handleQueryImageForNodeID called first time"]; XCTestExpectation * queryExpectation2 = [self expectationWithDescription:@"handleQueryImageForNodeID called second time"]; @@ -734,8 +916,11 @@ - (void)test003_ReceiveQueryImageRequestWhileHandlingBDX_RespondImplicitBusy // in the middle of doing BDX with device1, this actually responds with Busy. // 5) Error out of the device1 transfer. // 6) Wait for device2 to query us again. - __auto_type * device1 = sConnectedDevice1; - __auto_type * device2 = sConnectedDevice2; + __auto_type * runner1 = [[MTROTARequestorAppRunner alloc] initWithPayload:kOnboardingPayload1 testcase:self]; + __auto_type * device1 = [runner1 commissionWithNodeID:@(kDeviceId1)]; + + __auto_type * runner2 = [[MTROTARequestorAppRunner alloc] initWithPayload:kOnboardingPayload2 testcase:self]; + __auto_type * device2 = [runner2 commissionWithNodeID:@(kDeviceId2)]; __block XCTestExpectation * announceResponseExpectation2; XCTestExpectation * queryExpectation1 = [self expectationWithDescription:@"handleQueryImageForNodeID called first time"]; @@ -823,7 +1008,8 @@ - (void)test004_DoBDXTransferDenyUpdateRequest // 5) Send the data as the BDX transfer proceeds. // 6) When device invokes ApplyUpdateRequest, respond with Discontinue so // that the update does not actually proceed. - __auto_type * device = sConnectedDevice1; + __auto_type * runner = [[MTROTARequestorAppRunner alloc] initWithPayload:kOnboardingPayload1 testcase:self]; + __auto_type * device = [runner commissionWithNodeID:@(kDeviceId1)]; // First, create an image. Make it at least 4096 bytes long, so we get // multiple BDX blocks going. @@ -840,7 +1026,7 @@ - (void)test004_DoBDXTransferDenyUpdateRequest __auto_type * checker = [[MTROTAProviderTransferChecker alloc] initWithRawImagePath:rawImagePath - otaImageDownloadFilePath:kOtaDownloadedFilePath1 + otaImageDownloadFilePath:runner.downloadFilePath nodeID:@(kDeviceId1) softwareVersion:kUpdatedSoftwareVersion_5 softwareVersionString:kUpdatedSoftwareVersionString_5 @@ -888,17 +1074,17 @@ - (void)test005_DoBDXTransferAllowUpdateRequest // 7) When device invokes ApplyUpdateRequest, respond with Proceed so that the update proceeds // 8) Wait for the app to restart and wait for the NotifyUpdateApplied message to confirm the app has updated to the new version - // This test expects a pre-generated raw image at otaRawImagePath. - NSString * otaRawImagePath = @"/tmp/ota-raw-image-v5"; + NSString * otaRawImagePath = [self createRawImageWithVersion:kUpdatedSoftwareVersion_5]; // Check whether the ota raw image exists at otaRawImagePath XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:otaRawImagePath]); - __auto_type * device = sConnectedDevice1; + __auto_type * runner = [[MTROTARequestorAppRunner alloc] initWithPayload:kOnboardingPayload1 testcase:self]; + __auto_type * device = [runner commissionWithNodeID:@(kDeviceId1)]; __auto_type * checker = [[MTROTAProviderTransferChecker alloc] initWithRawImagePath:otaRawImagePath - otaImageDownloadFilePath:kOtaDownloadedFilePath1 + otaImageDownloadFilePath:runner.downloadFilePath nodeID:@(kDeviceId1) softwareVersion:kUpdatedSoftwareVersion_5 softwareVersionString:kUpdatedSoftwareVersionString_5 @@ -928,10 +1114,6 @@ - (void)test005_DoBDXTransferAllowUpdateRequest - (void)test006_DoBDXTransferWithTwoOTARequesters { - // Note: This test has a dependency on test005_DoBDXTransferAllowUpdateRequest since we update device1 to version - // number 5 in the above test. We reuse device1 for this test and we need to use an OTA image with a higher version number (10) - // for device1 to update itself again. We need to fix this when we want to run tests out of order. - // In this test, we test BDX transfers between one provider and two OTA requestors device1 and device2. // // 1) We announce ourselves to device1 first. @@ -946,9 +1128,8 @@ - (void)test006_DoBDXTransferWithTwoOTARequesters // 10) At this point, we set the apply update handlers for device2. // 11) Device2 applies the update and reboots with its new image. - // This test expects a pre-generated raw image at otaRawImagePath1 for device1 and at otaRawImagePath2 for device2. - NSString * otaRawImagePath1 = @"/tmp/ota-raw-image-v10"; - NSString * otaRawImagePath2 = @"/tmp/ota-raw-image-v5"; + NSString * otaRawImagePath1 = [self createRawImageWithVersion:kUpdatedSoftwareVersion_10]; + NSString * otaRawImagePath2 = [self createRawImageWithVersion:kUpdatedSoftwareVersion_5]; // Check whether the ota raw image exists at otaRawImagePath1 and otaRawImagePath2 XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:otaRawImagePath1]); @@ -985,40 +1166,8 @@ - (void)test006_DoBDXTransferWithTwoOTARequesters __block XCTestExpectation * announceResponseExpectation2; - NSString * imagePath1 = [otaRawImagePath1 stringByReplacingOccurrencesOfString:@"raw-image" withString:@"image"]; - - NSString * imagePath2 = [otaRawImagePath2 stringByReplacingOccurrencesOfString:@"raw-image" withString:@"image"]; - - // Find the right absolute path to our ota_image_tool.py script. PWD should - // point to our src/darwin/Framework, while the script is in - // src/app/ota_image_tool.py. - NSString * pwd = [[NSProcessInfo processInfo] environment][@"PWD"]; - NSString * imageToolPath = [NSString - pathWithComponents:@[ [pwd substringToIndex:(pwd.length - @"darwin/Framework".length)], @"app", @"ota_image_tool.py" ]]; - - NSTask * task1 = [[NSTask alloc] init]; - [task1 setLaunchPath:imageToolPath]; - [task1 setArguments:@[ - @"create", @"-v", @"0xFFF1", @"-p", @"0x8001", @"-vn", [kUpdatedSoftwareVersion_10 stringValue], @"-vs", - kUpdatedSoftwareVersionString_10, @"-da", @"sha256", otaRawImagePath1, imagePath1 - ]]; - NSError * launchError = nil; - [task1 launchAndReturnError:&launchError]; - XCTAssertNil(launchError); - [task1 waitUntilExit]; - XCTAssertEqual([task1 terminationStatus], 0); - - NSTask * task2 = [[NSTask alloc] init]; - [task2 setLaunchPath:imageToolPath]; - [task2 setArguments:@[ - @"create", @"-v", @"0xFFF1", @"-p", @"0x8001", @"-vn", [kUpdatedSoftwareVersion_5 stringValue], @"-vs", - kUpdatedSoftwareVersionString_5, @"-da", @"sha256", otaRawImagePath2, imagePath2 - ]]; - launchError = nil; - [task2 launchAndReturnError:&launchError]; - XCTAssertNil(launchError); - [task2 waitUntilExit]; - XCTAssertEqual([task2 terminationStatus], 0); + NSString * imagePath1 = [self createImageFromRawImage:otaRawImagePath1 withVersion:kUpdatedSoftwareVersion_10]; + NSString * imagePath2 = [self createImageFromRawImage:otaRawImagePath2 withVersion:kUpdatedSoftwareVersion_5]; NSData * updateToken1 = [sOTAProviderDelegate generateUpdateToken]; NSData * updateToken2 = [sOTAProviderDelegate generateUpdateToken]; @@ -1027,8 +1176,12 @@ - (void)test006_DoBDXTransferWithTwoOTARequesters __block uint64_t imageSize; __block uint32_t lastBlockIndex = UINT32_MAX; const uint16_t busyDelay = 30; // 30 second - __auto_type * device1 = sConnectedDevice1; - __auto_type * device2 = sConnectedDevice2; + + __auto_type * runner1 = [[MTROTARequestorAppRunner alloc] initWithPayload:kOnboardingPayload1 testcase:self]; + __auto_type * device1 = [runner1 commissionWithNodeID:@(kDeviceId1)]; + + __auto_type * runner2 = [[MTROTARequestorAppRunner alloc] initWithPayload:kOnboardingPayload2 testcase:self]; + __auto_type * device2 = [runner2 commissionWithNodeID:@(kDeviceId2)]; // This to keep track of whether queryImageHandler for device 2 was called or not. The first time it's called we will // fulfill queryExpectation2 and proceed with BDX for device 1. @@ -1238,7 +1391,7 @@ - (void)test006_DoBDXTransferWithTwoOTARequesters // Device1 is updated to version 10 and device2 to version 5. NSNumber * kSoftwareVersion = (isDeviceID1) ? kUpdatedSoftwareVersion_10 : kUpdatedSoftwareVersion_5; NSString * otaImageFilePath = (isDeviceID1) ? otaRawImagePath1 : otaRawImagePath2; - NSString * otaDownloadedFilePath = (isDeviceID1) ? kOtaDownloadedFilePath1 : kOtaDownloadedFilePath2; + NSString * otaDownloadedFilePath = (isDeviceID1) ? runner1.downloadFilePath : runner2.downloadFilePath; XCTAssertEqual(controller, sController); XCTAssertEqualObjects(params.updateToken, updateToken); @@ -1343,19 +1496,19 @@ - (void)test007_DoBDXTransferIncrementalOtaUpdate // 4) Device3 completes the BDX transfer // 5) Device3 applies the update and reboots with the new image with version number 10 - // This test expects a pre-generated raw image at otaRawImagePath1 and a raw image at otaRawImagePath2 - NSString * otaRawImagePath1 = @"/tmp/ota-raw-image-v5"; - NSString * otaRawImagePath2 = @"/tmp/ota-raw-image-v10"; + NSString * otaRawImagePath1 = [self createRawImageWithVersion:kUpdatedSoftwareVersion_5]; + NSString * otaRawImagePath2 = [self createRawImageWithVersion:kUpdatedSoftwareVersion_10]; // Check whether the ota raw image exists at otaRawImagePath1 and otaRawImagePath2 XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:otaRawImagePath1]); XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:otaRawImagePath2]); - __auto_type * device = sConnectedDevice3; + __auto_type * runner = [[MTROTARequestorAppRunner alloc] initWithPayload:kOnboardingPayload3 testcase:self]; + __auto_type * device = [runner commissionWithNodeID:@(kDeviceId3)]; __auto_type * checker = [[MTROTAProviderTransferChecker alloc] initWithRawImagePath:otaRawImagePath1 - otaImageDownloadFilePath:kOtaDownloadedFilePath3 + otaImageDownloadFilePath:runner.downloadFilePath nodeID:@(kDeviceId3) softwareVersion:kUpdatedSoftwareVersion_5 softwareVersionString:kUpdatedSoftwareVersionString_5 @@ -1386,7 +1539,7 @@ - (void)test007_DoBDXTransferIncrementalOtaUpdate __auto_type * checker1 = [[MTROTAProviderTransferChecker alloc] initWithRawImagePath:otaRawImagePath2 - otaImageDownloadFilePath:kOtaDownloadedFilePath3 + otaImageDownloadFilePath:runner.downloadFilePath nodeID:@(kDeviceId3) softwareVersion:kUpdatedSoftwareVersion_10 softwareVersionString:kUpdatedSoftwareVersionString_10 @@ -1417,18 +1570,9 @@ - (void)test007_DoBDXTransferIncrementalOtaUpdate - (void)test999_TearDown { - __auto_type * device = [MTRBaseDevice deviceWithNodeID:@(kDeviceId1) controller:sController]; - ResetCommissionee(device, dispatch_get_main_queue(), self, kTimeoutInSeconds); - - device = [MTRBaseDevice deviceWithNodeID:@(kDeviceId2) controller:sController]; - ResetCommissionee(device, dispatch_get_main_queue(), self, kTimeoutInSeconds); - - device = [MTRBaseDevice deviceWithNodeID:@(kDeviceId3) controller:sController]; - ResetCommissionee(device, dispatch_get_main_queue(), self, kTimeoutInSeconds); - [[self class] shutdownStack]; } -#endif +#endif // ENABLE_OTA_TESTS @end