16
16
17
17
#import < Matter/Matter.h>
18
18
19
+ #import < dns_sd.h>
19
20
#import < os/lock.h>
20
21
21
22
#import " MTRDeviceControllerLocalTestStorage.h"
@@ -207,6 +208,109 @@ - (void)issueOperationalCertificateForRequest:(MTROperationalCSRInfo *)csrInfo
207
208
208
209
@end
209
210
211
+ @interface MTRPerControllerStorageTestsOperationalBrowser : NSObject
212
+
213
+ // expectedNodeID should be a 16-char uppercase hex string encoding the 64-bit
214
+ // node ID.
215
+ - (instancetype )initWithNodeID : (NSString *)expectedNodeID ;
216
+ - (void )shutdown ;
217
+
218
+ @property (nonatomic , readwrite ) NSString * expectedNodeID;
219
+ @property (nonatomic , readwrite , nullable ) XCTestExpectation * addedExpectation;
220
+ @property (nonatomic , readwrite , nullable ) XCTestExpectation * removedExpectation;
221
+
222
+ - (void )onBrowse : (DNSServiceFlags)flags error : (DNSServiceErrorType)error instanceName : (const char *)instanceName ;
223
+
224
+ @end
225
+
226
+ static void OnBrowse (DNSServiceRef serviceRef, DNSServiceFlags flags, uint32_t interfaceId,
227
+ DNSServiceErrorType error, const char * name, const char * type, const char * domain, void * context)
228
+ {
229
+ __auto_type * self = (__bridge MTRPerControllerStorageTestsOperationalBrowser *) context;
230
+ [self onBrowse: flags error: error instanceName: name];
231
+ }
232
+
233
+ @implementation MTRPerControllerStorageTestsOperationalBrowser {
234
+ DNSServiceRef _browseRef;
235
+ }
236
+
237
+ - (instancetype )initWithNodeID : (NSString *)expectedNodeID
238
+ {
239
+ if (!(self = [super init ])) {
240
+ return nil ;
241
+ }
242
+
243
+ _expectedNodeID = expectedNodeID;
244
+
245
+ __auto_type queue = dispatch_get_main_queue ();
246
+
247
+ __auto_type err = DNSServiceBrowse (&_browseRef, /* DNSServiceFlags = */ 0 , kDNSServiceInterfaceIndexAny , " _matter._tcp" , " local." , OnBrowse, (__bridge void *) self);
248
+ XCTAssertEqual (err, kDNSServiceErr_NoError );
249
+ if (err != kDNSServiceErr_NoError ) {
250
+ return nil ;
251
+ }
252
+
253
+ err = DNSServiceSetDispatchQueue (_browseRef, queue);
254
+ XCTAssertEqual (err, kDNSServiceErr_NoError );
255
+ if (err != kDNSServiceErr_NoError ) {
256
+ DNSServiceRefDeallocate (_browseRef);
257
+ _browseRef = nil ;
258
+ return nil ;
259
+ }
260
+
261
+ return self;
262
+ }
263
+
264
+ - (void )shutdown
265
+ {
266
+ if (_browseRef) {
267
+ DNSServiceRefDeallocate (_browseRef);
268
+ _browseRef = nil ;
269
+ }
270
+ }
271
+
272
+ - (void )onBrowse : (DNSServiceFlags)flags error : (DNSServiceErrorType)error instanceName : (const char *)instanceName
273
+ {
274
+ XCTAssertEqual (error, kDNSServiceErr_NoError );
275
+ if (error != kDNSServiceErr_NoError ) {
276
+ DNSServiceRefDeallocate (_browseRef);
277
+ _browseRef = nil ;
278
+ return ;
279
+ }
280
+
281
+ __auto_type len = strlen (instanceName);
282
+ XCTAssertEqual (len, 33 ); // Matter instance names are 33 chars.
283
+
284
+ if (len != 33 ) {
285
+ return ;
286
+ }
287
+
288
+ // Skip over compressed fabric id and dash.
289
+ // TODO: Consider checking the compressed fabric ID? That's a bit hard to
290
+ // do, in general, since it depends on our keys.
291
+ const char * nodeID = &instanceName[17 ];
292
+ NSString * browsedNode = [NSString stringWithUTF8String: nodeID];
293
+ if (![browsedNode isEqual: self .expectedNodeID]) {
294
+ return ;
295
+ }
296
+
297
+ if (flags & kDNSServiceFlagsAdd ) {
298
+ if (self.addedExpectation ) {
299
+ XCTestExpectation * expectation = self.addedExpectation ;
300
+ self.addedExpectation = nil ;
301
+ [expectation fulfill ];
302
+ }
303
+ } else {
304
+ if (self.removedExpectation ) {
305
+ XCTestExpectation * expectation = self.removedExpectation ;
306
+ self.removedExpectation = nil ;
307
+ [expectation fulfill ];
308
+ }
309
+ }
310
+ }
311
+
312
+ @end
313
+
210
314
@interface MTRPerControllerStorageTests : MTRTestCase
211
315
@end
212
316
@@ -1665,6 +1769,12 @@ - (void)test011_TestDataStoreMTRDeviceWithStorageBehaviorOptimizationDisabled
1665
1769
// suspension tests to a different file.
1666
1770
- (void )test012_startSuspended
1667
1771
{
1772
+ // Needs to match the 888 == 0x378 for the node ID below.
1773
+ __auto_type * operationalBrowser = [[MTRPerControllerStorageTestsOperationalBrowser alloc ] initWithNodeID: @" 0000000000000378" ];
1774
+ XCTestExpectation * initialAdvertisingExpectation = [self expectationWithDescription: @" Controller advertising initially" ];
1775
+ operationalBrowser.addedExpectation = initialAdvertisingExpectation;
1776
+ initialAdvertisingExpectation.inverted = YES ; // We should not in fact advertise, since we are suspended.
1777
+
1668
1778
NSError * error;
1669
1779
__auto_type * storageDelegate = [[MTRTestPerControllerStorage alloc ] initWithControllerID: [NSUUID UUID ]];
1670
1780
__auto_type * controller = [self startControllerWithRootKeys: [[MTRTestKeys alloc ] init ]
@@ -1675,6 +1785,7 @@ - (void)test012_startSuspended
1675
1785
caseAuthenticatedTags: nil
1676
1786
paramsModifier: ^(MTRDeviceControllerExternalCertificateParameters * params) {
1677
1787
params.startSuspended = YES ;
1788
+ params.shouldAdvertiseOperational = YES ;
1678
1789
}
1679
1790
error: &error];
1680
1791
@@ -1691,17 +1802,28 @@ - (void)test012_startSuspended
1691
1802
[controller setupCommissioningSessionWithPayload: payload newNodeID: @(17 ) error: &error];
1692
1803
XCTAssertNotNil (error);
1693
1804
1805
+ [self waitForExpectations: @[ initialAdvertisingExpectation ] timeout: kTimeoutInSeconds ];
1806
+
1694
1807
[controller shutdown ];
1808
+
1809
+ [operationalBrowser shutdown ];
1695
1810
}
1696
1811
1697
1812
- (void )test013_suspendDevices
1698
1813
{
1814
+ // getMTRDevice uses "123" for the node ID of the controller, which is hex 0x7B
1815
+ __auto_type * operationalBrowser = [[MTRPerControllerStorageTestsOperationalBrowser alloc ] initWithNodeID: @" 000000000000007B" ];
1816
+ XCTestExpectation * initialAdvertisingExpectation = [self expectationWithDescription: @" Controller advertising initially" ];
1817
+ operationalBrowser.addedExpectation = initialAdvertisingExpectation;
1818
+
1699
1819
NSNumber * deviceID = @(17 );
1700
1820
__auto_type * device = [self getMTRDevice: deviceID];
1701
1821
__auto_type * controller = device.deviceController ;
1702
1822
1703
1823
XCTAssertFalse (controller.suspended );
1704
1824
1825
+ [self waitForExpectations: @[ initialAdvertisingExpectation ] timeout: kTimeoutInSeconds ];
1826
+
1705
1827
__auto_type queue = dispatch_get_main_queue ();
1706
1828
__auto_type * delegate = [[MTRDeviceTestDelegate alloc ] init ];
1707
1829
@@ -1757,6 +1879,9 @@ - (void)test013_suspendDevices
1757
1879
}
1758
1880
});
1759
1881
1882
+ XCTestExpectation * advertisingStoppedExpectation = [self expectationWithDescription: @" Controller stopped advertising" ];
1883
+ operationalBrowser.removedExpectation = advertisingStoppedExpectation;
1884
+
1760
1885
[controller suspend ];
1761
1886
XCTAssertTrue (controller.suspended );
1762
1887
@@ -1767,7 +1892,7 @@ - (void)test013_suspendDevices
1767
1892
[toggle2Expectation fulfill ];
1768
1893
}];
1769
1894
1770
- [self waitForExpectations: @[ becameUnreachableExpectation, toggle2Expectation, suspendedExpectation, browseStoppedExpectation ] timeout: kTimeoutInSeconds ];
1895
+ [self waitForExpectations: @[ becameUnreachableExpectation, toggle2Expectation, suspendedExpectation, browseStoppedExpectation, advertisingStoppedExpectation ] timeout: kTimeoutInSeconds ];
1771
1896
1772
1897
XCTestExpectation * newSubscriptionExpectation = [self expectationWithDescription: @" Subscription has been set up again" ];
1773
1898
XCTestExpectation * newReachableExpectation = [self expectationWithDescription: @" Device became reachable again" ];
@@ -1790,10 +1915,13 @@ - (void)test013_suspendDevices
1790
1915
}
1791
1916
});
1792
1917
1918
+ XCTestExpectation * advertisingResumedExpectation = [self expectationWithDescription: @" Controller resumed advertising" ];
1919
+ operationalBrowser.addedExpectation = advertisingResumedExpectation;
1920
+
1793
1921
[controller resume ];
1794
1922
XCTAssertFalse (controller.suspended );
1795
1923
1796
- [self waitForExpectations: @[ newSubscriptionExpectation, newReachableExpectation, resumedExpectation, browseRestartedExpectation ] timeout: kSubscriptionTimeoutInSeconds ];
1924
+ [self waitForExpectations: @[ newSubscriptionExpectation, newReachableExpectation, resumedExpectation, browseRestartedExpectation, advertisingResumedExpectation ] timeout: kSubscriptionTimeoutInSeconds ];
1797
1925
1798
1926
MTRSetLogCallback (MTRLogTypeProgress, nil );
1799
1927
@@ -1814,6 +1942,8 @@ - (void)test013_suspendDevices
1814
1942
ResetCommissionee (baseDevice, queue, self, kTimeoutInSeconds );
1815
1943
1816
1944
[controller shutdown ];
1945
+
1946
+ [operationalBrowser shutdown ];
1817
1947
}
1818
1948
1819
1949
// TODO: This might want to go in a separate test file, with some shared setup
0 commit comments