123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451 |
- #import "RLMSyncTestCase.h"
- #import "RLMTestUtils.h"
- #import "RLMSyncSessionRefreshHandle+ObjectServerTests.h"
- #import "RLMSyncUser+ObjectServerTests.h"
- #import "RLMObjectSchema_Private.hpp"
- #import "RLMRealm+Sync.h"
- #import "RLMRealmConfiguration_Private.h"
- #import "RLMRealmUtil.hpp"
- #import "RLMRealm_Dynamic.h"
- #import "RLMRealm_Private.hpp"
- #import "RLMSchema_Private.h"
- #import "RLMSyncUtil_Private.h"
- #import "shared_realm.hpp"
- #pragma mark - Test objects
- @interface PartialSyncObjectA : RLMObject
- @property NSInteger number;
- @property NSString *string;
- + (instancetype)objectWithNumber:(NSInteger)number string:(NSString *)string;
- @end
- @interface PartialSyncObjectB : RLMObject
- @property NSInteger number;
- @property NSString *firstString;
- @property NSString *secondString;
- + (instancetype)objectWithNumber:(NSInteger)number firstString:(NSString *)first secondString:(NSString *)second;
- @end
- @implementation PartialSyncObjectA
- + (instancetype)objectWithNumber:(NSInteger)number string:(NSString *)string {
- PartialSyncObjectA *object = [[PartialSyncObjectA alloc] init];
- object.number = number;
- object.string = string;
- return object;
- }
- @end
- @implementation PartialSyncObjectB
- + (instancetype)objectWithNumber:(NSInteger)number firstString:(NSString *)first secondString:(NSString *)second {
- PartialSyncObjectB *object = [[PartialSyncObjectB alloc] init];
- object.number = number;
- object.firstString = first;
- object.secondString = second;
- return object;
- }
- @end
- @interface RLMObjectServerTests : RLMSyncTestCase
- @end
- @implementation RLMObjectServerTests
- #pragma mark - Authentication and Tokens
- - (void)testUsernamePasswordAuthentication {
- RLMSyncUser *firstUser = [self logInUserForCredentials:[RLMSyncTestCase basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:YES]
- server:[RLMSyncTestCase authServerURL]];
- RLMSyncUser *secondUser = [self logInUserForCredentials:[RLMSyncTestCase basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:NO]
- server:[RLMSyncTestCase authServerURL]];
-
- XCTAssertTrue([firstUser.identity isEqualToString:secondUser.identity]);
-
- XCTAssertEqualObjects(firstUser.authenticationServer, [RLMSyncTestCase authServerURL]);
- XCTAssertFalse(firstUser.isAdmin);
- }
- - (void)testAdminTokenAuthentication {
- RLMSyncCredentials *credentials = [RLMSyncCredentials credentialsWithAccessToken:self.adminToken identity:@"test"];
- XCTAssertNotNil(credentials);
- RLMSyncUser *user = [self logInUserForCredentials:credentials server:[RLMObjectServerTests authServerURL]];
- XCTAssertTrue(user.isAdmin);
- }
- - (void)testCustomRefreshTokenAuthentication {
- RLMSyncCredentials *credentials = [RLMSyncCredentials credentialsWithCustomRefreshToken:@"token" identity:@"custom_identity1" isAdmin:NO];
- XCTAssertNotNil(credentials);
- RLMSyncUser *user = [self logInUserForCredentials:credentials server:[RLMObjectServerTests authServerURL]];
- XCTAssertEqualObjects(user.refreshToken, @"token");
- XCTAssertEqualObjects(user.identity, @"custom_identity1");
- XCTAssertFalse(user.isAdmin);
- credentials = [RLMSyncCredentials credentialsWithCustomRefreshToken:@"token" identity:@"custom_identity2" isAdmin:YES];
- XCTAssertNotNil(credentials);
- user = [self logInUserForCredentials:credentials server:[RLMObjectServerTests authServerURL]];
- XCTAssertEqualObjects(user.refreshToken, @"token");
- XCTAssertEqualObjects(user.identity, @"custom_identity2");
- XCTAssertTrue(user.isAdmin);
- }
- - (void)testInvalidPasswordAuthentication {
- [self logInUserForCredentials:[RLMSyncTestCase basicCredentialsWithName:NSStringFromSelector(_cmd) register:YES]
- server:[RLMSyncTestCase authServerURL]];
- RLMSyncCredentials *credentials = [RLMSyncCredentials credentialsWithUsername:NSStringFromSelector(_cmd)
- password:@"INVALID_PASSWORD"
- register:NO];
- XCTestExpectation *expectation = [self expectationWithDescription:@""];
- [RLMSyncUser logInWithCredentials:credentials
- authServerURL:[RLMObjectServerTests authServerURL]
- onCompletion:^(RLMSyncUser *user, NSError *error) {
- XCTAssertNil(user);
- XCTAssertNotNil(error);
- XCTAssertEqual(error.domain, RLMSyncAuthErrorDomain);
- XCTAssertEqual(error.code, RLMSyncAuthErrorInvalidCredential);
- XCTAssertNotNil(error.localizedDescription);
- [expectation fulfill];
- }];
- [self waitForExpectationsWithTimeout:2.0 handler:nil];
- }
- - (void)testNonExistingUsernameAuthentication {
- RLMSyncCredentials *credentials = [RLMSyncTestCase basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:NO];
- XCTestExpectation *expectation = [self expectationWithDescription:@""];
- [RLMSyncUser logInWithCredentials:credentials
- authServerURL:[RLMObjectServerTests authServerURL]
- onCompletion:^(RLMSyncUser *user, NSError *error) {
- XCTAssertNil(user);
- XCTAssertNotNil(error);
- XCTAssertEqual(error.domain, RLMSyncAuthErrorDomain);
- XCTAssertEqual(error.code, RLMSyncAuthErrorInvalidCredential);
- XCTAssertNotNil(error.localizedDescription);
- [expectation fulfill];
- }];
- [self waitForExpectationsWithTimeout:2.0 handler:nil];
- }
- - (void)testExistingUsernameRegistration {
- RLMSyncCredentials *credentials = [RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:YES];
- [self logInUserForCredentials:credentials server:[RLMSyncTestCase authServerURL]];
- XCTestExpectation *expectation = [self expectationWithDescription:@""];
- [RLMSyncUser logInWithCredentials:credentials
- authServerURL:[RLMObjectServerTests authServerURL]
- onCompletion:^(RLMSyncUser *user, NSError *error) {
- XCTAssertNil(user);
- XCTAssertNotNil(error);
- XCTAssertEqual(error.domain, RLMSyncAuthErrorDomain);
- XCTAssertEqual(error.code, RLMSyncAuthErrorInvalidCredential);
- XCTAssertNotNil(error.localizedDescription);
- [expectation fulfill];
- }];
- [self waitForExpectationsWithTimeout:2.0 handler:nil];
- }
- - (void)testSyncErrorHandlerErrorDomain {
- RLMSyncUser *user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:YES]
- server:[RLMObjectServerTests authServerURL]];
- XCTAssertNotNil(user);
- NSURL *realmURL = [NSURL URLWithString:@"realm://127.0.0.1:9080/THE_PATH_USER_DONT_HAVE_ACCESS_TO/test"];
- RLMRealmConfiguration *c = [user configurationWithURL:realmURL fullSynchronization:true];
- NSError *error = nil;
- __attribute__((objc_precise_lifetime)) RLMRealm *realm = [RLMRealm realmWithConfiguration:c error:&error];
- XCTAssertNil(error);
- XCTAssertTrue(realm.isEmpty);
- XCTestExpectation *expectation = [self expectationWithDescription:@""];
- [RLMSyncManager sharedManager].errorHandler = ^(__unused NSError *error,
- __unused RLMSyncSession *session) {
- XCTAssertTrue([error.domain isEqualToString:RLMSyncErrorDomain]);
- XCTAssertFalse([[error.userInfo[kRLMSyncUnderlyingErrorKey] domain] isEqualToString:RLMSyncErrorDomain]);
- [expectation fulfill];
- };
- [self waitForExpectationsWithTimeout:2.0 handler:nil];
- }
- - (void)testPreemptiveTokenRefresh {
-
- __block NSInteger refreshCount = 0;
- __block NSInteger errorCount = 0;
- [RLMSyncManager sharedManager].errorHandler = ^(__unused NSError *error,
- __unused RLMSyncSession *session) {
- errorCount++;
- };
- __block XCTestExpectation *ex;
- [RLMSyncSessionRefreshHandle calculateFireDateUsingTestLogic:YES
- blockOnRefreshCompletion:^(BOOL success) {
- XCTAssertTrue(success);
- if (refreshCount++ == 3) {
- [ex fulfill];
- }
- }];
-
- NSURL *url = REALM_URL();
- RLMSyncUser *user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:true]
- server:[RLMObjectServerTests authServerURL]];
- __attribute__((objc_precise_lifetime)) RLMRealm *realm = [self openRealmForURL:url user:user];
- ex = [self expectationWithDescription:@"Timer fired"];
- [self waitForExpectationsWithTimeout:10 handler:nil];
- XCTAssertTrue(errorCount == 0);
- XCTAssertTrue(refreshCount >= 4);
- }
- - (void)testLoginConnectionTimeoutFromManager {
-
- NSString *userName = NSStringFromSelector(_cmd);
- @autoreleasepool {
- RLMSyncCredentials *credentials = [RLMObjectServerTests basicCredentialsWithName:userName register:YES];
- RLMSyncUser *user = [self logInUserForCredentials:credentials server:[NSURL URLWithString:@"http://127.0.0.1:9080"]];
- [user logOut];
- }
- RLMSyncTimeoutOptions *timeoutOptions = [RLMSyncTimeoutOptions new];
-
- NSURL *authURL = [NSURL URLWithString:@"http://127.0.0.1:9082"];
-
- timeoutOptions.connectTimeout = 1000.0;
- RLMSyncManager.sharedManager.timeoutOptions = timeoutOptions;
- RLMSyncCredentials *credentials = [RLMObjectServerTests basicCredentialsWithName:userName register:NO];
- XCTestExpectation *ex = [self expectationWithDescription:@"Login should time out"];
- [RLMSyncUser logInWithCredentials:credentials authServerURL:authURL
- onCompletion:^(RLMSyncUser *user, NSError *error) {
- XCTAssertNil(user);
- XCTAssertNotNil(error);
- XCTAssertEqualObjects(error.domain, NSURLErrorDomain);
- XCTAssertEqual(error.code, NSURLErrorTimedOut);
- [ex fulfill];
- }];
- [self waitForExpectationsWithTimeout:2.0 handler:nil];
-
- timeoutOptions.connectTimeout = 3000.0;
- RLMSyncManager.sharedManager.timeoutOptions = timeoutOptions;
- ex = [self expectationWithDescription:@"Login should succeed"];
- [RLMSyncUser logInWithCredentials:credentials authServerURL:authURL
- onCompletion:^(RLMSyncUser *user, NSError *error) {
- [user logOut];
- XCTAssertNotNil(user);
- XCTAssertNil(error);
- [ex fulfill];
- }];
- [self waitForExpectationsWithTimeout:3.0 handler:nil];
- }
- - (void)testLoginConnectionTimeoutDirect {
-
- NSString *userName = NSStringFromSelector(_cmd);
- @autoreleasepool {
- RLMSyncCredentials *credentials = [RLMObjectServerTests basicCredentialsWithName:userName register:YES];
- RLMSyncUser *user = [self logInUserForCredentials:credentials server:[NSURL URLWithString:@"http://127.0.0.1:9080"]];
- [user logOut];
- }
-
- NSURL *authURL = [NSURL URLWithString:@"http://127.0.0.1:9082"];
-
- RLMSyncCredentials *credentials = [RLMObjectServerTests basicCredentialsWithName:userName register:NO];
- XCTestExpectation *ex = [self expectationWithDescription:@"Login should time out"];
- [RLMSyncUser logInWithCredentials:credentials authServerURL:authURL
- timeout:1.0 callbackQueue:dispatch_get_main_queue()
- onCompletion:^(RLMSyncUser *user, NSError *error) {
- XCTAssertNil(user);
- XCTAssertNotNil(error);
- XCTAssertEqualObjects(error.domain, NSURLErrorDomain);
- XCTAssertEqual(error.code, NSURLErrorTimedOut);
- [ex fulfill];
- }];
- [self waitForExpectationsWithTimeout:2.0 handler:nil];
-
- ex = [self expectationWithDescription:@"Login should succeed"];
- [RLMSyncUser logInWithCredentials:credentials authServerURL:authURL
- timeout:3.0 callbackQueue:dispatch_get_main_queue()
- onCompletion:^(RLMSyncUser *user, NSError *error) {
- [user logOut];
- XCTAssertNotNil(user);
- XCTAssertNil(error);
- [ex fulfill];
- }];
- [self waitForExpectationsWithTimeout:3.0 handler:nil];
- }
- #pragma mark - Users
- - (void)testBasicUserPersistence {
- XCTAssertNil([RLMSyncUser currentUser]);
- XCTAssertEqual([[RLMSyncUser allUsers] count], 0U);
- RLMSyncUser *user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:YES]
- server:[RLMObjectServerTests authServerURL]];
- XCTAssertNotNil(user);
- XCTAssertEqual([[RLMSyncUser allUsers] count], 1U);
- XCTAssertEqualObjects([RLMSyncUser allUsers], @{user.identity: user});
- XCTAssertEqualObjects([RLMSyncUser currentUser], user);
- RLMSyncUser *user2 = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:[NSStringFromSelector(_cmd) stringByAppendingString:@"2"]
- register:YES]
- server:[RLMObjectServerTests authServerURL]];
- XCTAssertEqual([[RLMSyncUser allUsers] count], 2U);
- NSDictionary *dict2 = @{user.identity: user, user2.identity: user2};
- XCTAssertEqualObjects([RLMSyncUser allUsers], dict2);
- RLMAssertThrowsWithReasonMatching([RLMSyncUser currentUser], @"currentUser cannot be called if more that one valid, logged-in user exists");
- }
- - (void)testCurrentUserLogout {
- XCTAssertNil([RLMSyncUser currentUser]);
- RLMSyncUser *user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:YES]
- server:[RLMObjectServerTests authServerURL]];
- XCTAssertNotNil(user);
- XCTAssertEqualObjects([RLMSyncUser currentUser], user);
- [user logOut];
- XCTAssertNil([RLMSyncUser currentUser]);
- }
- - (void)testUserGetSessionForValidURL {
- RLMSyncUser *user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:YES]
- server:[RLMObjectServerTests authServerURL]];
- NSURL *url = REALM_URL();
- [self openRealmForURL:url user:user immediatelyBlock:^{
- RLMSyncSession *session = [user sessionForURL:url];
- XCTAssertNotNil(session);
- }];
-
- RLMSyncSession *session = [user sessionForURL:url];
- XCTAssertNotNil(session);
- }
- - (void)testUserGetSessionForInvalidURL {
- RLMSyncUser *user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:YES]
- server:[RLMObjectServerTests authServerURL]];
- RLMSyncSession *badSession = [user sessionForURL:[NSURL URLWithString:@"realm://127.0.0.1:9080/noSuchRealm"]];
- XCTAssertNil(badSession);
- }
- - (void)testUserChangePassword {
- NSString *userName = NSStringFromSelector(_cmd);
- NSString *firstPassword = @"a";
- NSString *secondPassword = @"b";
-
-
- {
- RLMSyncCredentials *creds = [RLMSyncCredentials credentialsWithUsername:userName password:firstPassword
- register:YES];
- RLMSyncUser *user = [self logInUserForCredentials:creds
- server:[RLMObjectServerTests authServerURL]];
- XCTestExpectation *ex = [self expectationWithDescription:@"change password callback invoked"];
- [user changePassword:secondPassword completion:^(NSError * _Nullable error) {
- XCTAssertNil(error);
- [ex fulfill];
- }];
- [self waitForExpectationsWithTimeout:2.0 handler:nil];
- [user logOut];
- ex = [self expectationWithDescription:@"change password callback invoked"];
- [user changePassword:@"fail" completion:^(NSError * _Nullable error) {
- XCTAssertNotNil(error);
- [ex fulfill];
- }];
- [self waitForExpectationsWithTimeout:2.0 handler:nil];
- }
-
- {
- RLMSyncCredentials *creds = [RLMSyncCredentials credentialsWithUsername:userName password:firstPassword
- register:NO];
- XCTestExpectation *ex = [self expectationWithDescription:@"login callback invoked"];
- [RLMSyncUser logInWithCredentials:creds
- authServerURL:[RLMObjectServerTests authServerURL]
- onCompletion:^(RLMSyncUser *user, NSError *error) {
- XCTAssertNil(user);
- XCTAssertNotNil(error);
- XCTAssertEqual(error.domain, RLMSyncAuthErrorDomain);
- XCTAssertEqual(error.code, RLMSyncAuthErrorInvalidCredential);
- XCTAssertNotNil(error.localizedDescription);
- [ex fulfill];
- }];
- [self waitForExpectationsWithTimeout:2.0 handler:nil];
- }
-
- {
- RLMSyncCredentials *creds = [RLMSyncCredentials credentialsWithUsername:userName password:secondPassword
- register:NO];
- RLMSyncUser *user = [self logInUserForCredentials:creds server:[RLMObjectServerTests authServerURL]];
- XCTAssertNotNil(user);
- XCTAssertEqualObjects(RLMSyncUser.currentUser, user);
- [user logOut];
- XCTAssertNil(RLMSyncUser.currentUser);
- }
- }
- - (void)testOtherUserChangePassword {
-
- NSURL *url = [RLMObjectServerTests authServerURL];
- RLMSyncUser *adminUser = [self createAdminUserForURL:url username:[[NSUUID UUID] UUIDString]];
- NSString *username = NSStringFromSelector(_cmd);
- NSString *firstPassword = @"a";
- NSString *secondPassword = @"b";
- NSString *nonAdminUserID = nil;
-
- {
- RLMSyncCredentials *creds = [RLMSyncCredentials credentialsWithUsername:username
- password:firstPassword
- register:YES];
- RLMSyncUser *user = [self logInUserForCredentials:creds server:url];
- nonAdminUserID = user.identity;
- [user logOut];
- }
-
- {
- NSString *username2 = [NSString stringWithFormat:@"%@_2", username];
- RLMSyncCredentials *creds2 = [RLMSyncCredentials credentialsWithUsername:username2
- password:@"a"
- register:YES];
- RLMSyncUser *user2 = [self logInUserForCredentials:creds2 server:url];
- XCTestExpectation *ex = [self expectationWithDescription:@"change password callback invoked"];
- [user2 changePassword:@"foobar" forUserID:nonAdminUserID completion:^(NSError *error) {
- XCTAssertNotNil(error);
- [ex fulfill];
- }];
- [self waitForExpectationsWithTimeout:2.0 handler:nil];
- }
-
- {
- XCTestExpectation *ex = [self expectationWithDescription:@"change password callback invoked"];
- [adminUser changePassword:secondPassword forUserID:nonAdminUserID completion:^(NSError *error) {
- XCTAssertNil(error);
- [ex fulfill];
- }];
- [self waitForExpectationsWithTimeout:2.0 handler:nil];
- }
-
- {
- RLMSyncCredentials *creds = [RLMSyncCredentials credentialsWithUsername:username
- password:firstPassword
- register:NO];
- XCTestExpectation *ex = [self expectationWithDescription:@"login callback invoked"];
- [RLMSyncUser logInWithCredentials:creds
- authServerURL:[RLMObjectServerTests authServerURL]
- onCompletion:^(RLMSyncUser *user, NSError *error) {
- XCTAssertNil(user);
- XCTAssertNotNil(error);
- XCTAssertEqual(error.domain, RLMSyncAuthErrorDomain);
- XCTAssertEqual(error.code, RLMSyncAuthErrorInvalidCredential);
- XCTAssertNotNil(error.localizedDescription);
- [ex fulfill];
- }];
- [self waitForExpectationsWithTimeout:2.0 handler:nil];
- }
-
- {
- RLMSyncCredentials *creds = [RLMSyncCredentials credentialsWithUsername:username
- password:secondPassword
- register:NO];
- RLMSyncUser *user = [self logInUserForCredentials:creds server:[RLMObjectServerTests authServerURL]];
- XCTAssertNotNil(user);
- [user logOut];
- }
- }
- - (void)testRequestPasswordResetForRegisteredUser {
- NSString *userName = [NSStringFromSelector(_cmd) stringByAppendingString:@"@example.com"];
- RLMSyncCredentials *creds = [RLMSyncCredentials credentialsWithUsername:userName password:@"a" register:YES];
- [[self logInUserForCredentials:creds server:[RLMObjectServerTests authServerURL]] logOut];
- XCTestExpectation *ex = [self expectationWithDescription:@"callback invoked"];
- [RLMSyncUser requestPasswordResetForAuthServer:[RLMObjectServerTests authServerURL] userEmail:userName completion:^(NSError *error) {
- XCTAssertNil(error);
- [ex fulfill];
- }];
- [self waitForExpectationsWithTimeout:2.0 handler:nil];
- NSString *token = [self emailForAddress:userName];
- XCTAssertNotNil(token);
-
- ex = [self expectationWithDescription:@"callback invoked"];
- [RLMSyncUser completePasswordResetForAuthServer:[RLMObjectServerTests authServerURL] token:token password:@"new password"
- completion:^(NSError *error) {
- XCTAssertNil(error);
- [ex fulfill];
- }];
- [self waitForExpectationsWithTimeout:2.0 handler:nil];
-
- {
- RLMSyncCredentials *creds = [RLMSyncCredentials credentialsWithUsername:userName
- password:@"new password"
- register:NO];
- RLMSyncUser *user = [self logInUserForCredentials:creds server:[RLMObjectServerTests authServerURL]];
- XCTAssertNotNil(user);
- [user logOut];
- }
-
- ex = [self expectationWithDescription:@"callback invoked"];
- [RLMSyncUser completePasswordResetForAuthServer:[RLMObjectServerTests authServerURL] token:token password:@"new password 2"
- completion:^(NSError *error) {
- XCTAssertNotNil(error);
- [ex fulfill];
- }];
- [self waitForExpectationsWithTimeout:2.0 handler:nil];
- }
- - (void)testRequestPasswordResetForNonexistentUser {
- NSString *userName = [NSStringFromSelector(_cmd) stringByAppendingString:@"@example.com"];
- XCTestExpectation *ex = [self expectationWithDescription:@"callback invoked"];
- [RLMSyncUser requestPasswordResetForAuthServer:[RLMObjectServerTests authServerURL] userEmail:userName completion:^(NSError *error) {
-
- XCTAssertNil(error);
- [ex fulfill];
- }];
- [self waitForExpectationsWithTimeout:2.0 handler:nil];
-
- XCTAssertNil([self emailForAddress:userName]);
- }
- - (void)testRequestPasswordResetWithBadAuthURL {
- NSString *userName = [NSStringFromSelector(_cmd) stringByAppendingString:@"@example.com"];
- XCTestExpectation *ex = [self expectationWithDescription:@"callback invoked"];
- NSURL *badAuthUrl = [[RLMObjectServerTests authServerURL] URLByAppendingPathComponent:@"/bad"];
- [RLMSyncUser requestPasswordResetForAuthServer:badAuthUrl userEmail:userName completion:^(NSError *error) {
- XCTAssertNotNil(error);
- XCTAssertEqualObjects(error.userInfo[@"statusCode"], @404);
- [ex fulfill];
- }];
- [self waitForExpectationsWithTimeout:2.0 handler:nil];
- }
- - (void)testRequestConfirmEmailForRegisteredUser {
- NSString *userName = [NSStringFromSelector(_cmd) stringByAppendingString:@"@example.com"];
- RLMSyncCredentials *creds = [RLMSyncCredentials credentialsWithUsername:userName password:@"a" register:YES];
- [[self logInUserForCredentials:creds server:[RLMObjectServerTests authServerURL]] logOut];
-
- NSString *registrationToken = [self emailForAddress:userName];
- XCTAssertNotNil(registrationToken);
- XCTestExpectation *ex = [self expectationWithDescription:@"callback invoked"];
- [RLMSyncUser requestEmailConfirmationForAuthServer:[RLMObjectServerTests authServerURL]
- userEmail:userName completion:^(NSError *error) {
- XCTAssertNil(error);
- [ex fulfill];
- }];
- [self waitForExpectationsWithTimeout:2.0 handler:nil];
-
- NSString *token = [self emailForAddress:userName];
- XCTAssertNotNil(token);
- XCTAssertNotEqual(token, registrationToken);
-
- ex = [self expectationWithDescription:@"callback invoked"];
- [RLMSyncUser confirmEmailForAuthServer:[RLMObjectServerTests authServerURL] token:token
- completion:^(NSError *error) {
- XCTAssertNil(error);
- [ex fulfill];
- }];
- [self waitForExpectationsWithTimeout:2.0 handler:nil];
-
- ex = [self expectationWithDescription:@"callback invoked"];
- [RLMSyncUser confirmEmailForAuthServer:[RLMObjectServerTests authServerURL] token:token
- completion:^(NSError *error) {
- XCTAssertNotNil(error);
- [ex fulfill];
- }];
- [self waitForExpectationsWithTimeout:2.0 handler:nil];
- }
- - (void)testRequestConfirmEmailForNonexistentUser {
- NSString *userName = [NSStringFromSelector(_cmd) stringByAppendingString:@"@example.com"];
- XCTestExpectation *ex = [self expectationWithDescription:@"callback invoked"];
- [RLMSyncUser requestEmailConfirmationForAuthServer:[RLMObjectServerTests authServerURL]
- userEmail:userName completion:^(NSError *error) {
-
- XCTAssertNil(error);
- [ex fulfill];
- }];
- [self waitForExpectationsWithTimeout:2.0 handler:nil];
-
- XCTAssertNil([self emailForAddress:userName]);
- }
- - (void)testRetrieveUserInfo {
- NSString *nonAdminUsername = @"meela@realm.example.org";
- NSString *adminUsername = @"jyaku";
- NSString *pw = @"p";
- NSURL *server = [RLMObjectServerTests authServerURL];
-
- RLMSyncCredentials *c1 = [RLMSyncCredentials credentialsWithUsername:nonAdminUsername password:pw register:YES];
- RLMSyncUser *nonAdminUser = [self logInUserForCredentials:c1 server:server];
-
- __unused RLMSyncUser *adminUser = [self createAdminUserForURL:server username:adminUsername];
-
- RLMSyncUser *userDoingLookups = [self createAdminUserForURL:server username:[[NSUUID UUID] UUIDString]];
-
- XCTestExpectation *ex1 = [self expectationWithDescription:@"should be able to get info about non-admin user"];
- [userDoingLookups retrieveInfoForUser:nonAdminUsername
- identityProvider:RLMIdentityProviderUsernamePassword
- completion:^(RLMSyncUserInfo *info, NSError *err) {
- XCTAssertNil(err);
- XCTAssertNotNil(info);
- XCTAssertGreaterThan([info.accounts count], ((NSUInteger) 0));
- RLMSyncUserAccountInfo *acctInfo = [info.accounts firstObject];
- XCTAssertEqualObjects(acctInfo.providerUserIdentity, nonAdminUsername);
- XCTAssertEqualObjects(acctInfo.provider, RLMIdentityProviderUsernamePassword);
- XCTAssertFalse(info.isAdmin);
- [ex1 fulfill];
- }];
- [self waitForExpectationsWithTimeout:10 handler:nil];
-
- XCTestExpectation *ex2 = [self expectationWithDescription:@"should be able to get info about admin user"];
- [userDoingLookups retrieveInfoForUser:adminUsername
- identityProvider:RLMIdentityProviderDebug
- completion:^(RLMSyncUserInfo *info, NSError *err) {
- XCTAssertNil(err);
- XCTAssertNotNil(info);
- XCTAssertGreaterThan([info.accounts count], ((NSUInteger) 0));
- RLMSyncUserAccountInfo *acctInfo = [info.accounts firstObject];
- XCTAssertEqualObjects(acctInfo.providerUserIdentity, adminUsername);
- XCTAssertEqualObjects(acctInfo.provider, RLMIdentityProviderDebug);
- XCTAssertTrue(info.isAdmin);
- [ex2 fulfill];
- }];
- [self waitForExpectationsWithTimeout:10 handler:nil];
-
- XCTestExpectation *ex3 = [self expectationWithDescription:@"should fail for non-existent user"];
- [userDoingLookups retrieveInfoForUser:@"invalid_user@realm.example.org"
- identityProvider:RLMIdentityProviderUsernamePassword
- completion:^(RLMSyncUserInfo *info, NSError *err) {
- XCTAssertNotNil(err);
- XCTAssertEqualObjects(err.domain, RLMSyncAuthErrorDomain);
- XCTAssertEqual(err.code, RLMSyncAuthErrorUserDoesNotExist);
- XCTAssertNil(info);
- [ex3 fulfill];
- }];
- [self waitForExpectationsWithTimeout:10 handler:nil];
-
- XCTestExpectation *ex4 = [self expectationWithDescription:@"should fail for user without admin privileges"];
- [nonAdminUser retrieveInfoForUser:adminUsername
- identityProvider:RLMIdentityProviderUsernamePassword
- completion:^(RLMSyncUserInfo *info, NSError *err) {
- XCTAssertNotNil(err);
- XCTAssertEqualObjects(err.domain, RLMSyncAuthErrorDomain);
-
- XCTAssertEqual(err.code, RLMSyncAuthErrorUserDoesNotExist);
- XCTAssertNil(info);
- [ex4 fulfill];
- }];
- [self waitForExpectationsWithTimeout:10 handler:nil];
- }
- - (void)testLoginQueueForSuccessfulLogin {
-
- dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
- RLMSyncCredentials *c1 = [RLMSyncCredentials credentialsWithUsername:[[NSUUID UUID] UUIDString]
- password:@"p"
- register:YES];
- XCTestExpectation *ex1 = [self expectationWithDescription:@"User logs in successfully on background queue"];
- [RLMSyncUser logInWithCredentials:c1
- authServerURL:[RLMObjectServerTests authServerURL]
- timeout:30.0
- callbackQueue:queue
- onCompletion:^(RLMSyncUser *user, __unused NSError *error) {
- XCTAssertNotNil(user);
- XCTAssertFalse([NSThread isMainThread]);
- [ex1 fulfill];
- }];
- [self waitForExpectationsWithTimeout:2.0 handler:nil];
- RLMSyncCredentials *c2 = [RLMSyncCredentials credentialsWithUsername:[[NSUUID UUID] UUIDString]
- password:@"p"
- register:YES];
- XCTestExpectation *ex2 = [self expectationWithDescription:@"User logs in successfully on main queue"];
- [RLMSyncUser logInWithCredentials:c2
- authServerURL:[RLMObjectServerTests authServerURL]
- timeout:30.0
- callbackQueue:dispatch_get_main_queue()
- onCompletion:^(RLMSyncUser *user, __unused NSError *error) {
- XCTAssertNotNil(user);
- XCTAssertTrue([NSThread isMainThread]);
- [ex2 fulfill];
- }];
- [self waitForExpectationsWithTimeout:2.0 handler:nil];
- }
- - (void)testLoginQueueForFailedLogin {
-
- dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
- RLMSyncCredentials *c1 = [RLMSyncCredentials credentialsWithUsername:[[NSUUID UUID] UUIDString]
- password:@"p"
- register:NO];
- XCTestExpectation *ex1 = [self expectationWithDescription:@"Error returned on background queue"];
- [RLMSyncUser logInWithCredentials:c1
- authServerURL:[RLMObjectServerTests authServerURL]
- timeout:30.0
- callbackQueue:queue
- onCompletion:^(__unused RLMSyncUser *user, NSError *error) {
- XCTAssertNotNil(error);
- XCTAssertFalse([NSThread isMainThread]);
- [ex1 fulfill];
- }];
- [self waitForExpectationsWithTimeout:2.0 handler:nil];
- RLMSyncCredentials *c2 = [RLMSyncCredentials credentialsWithUsername:[[NSUUID UUID] UUIDString]
- password:@"p"
- register:NO];
- XCTestExpectation *ex2 = [self expectationWithDescription:@"Error returned on main queue"];
- [RLMSyncUser logInWithCredentials:c2
- authServerURL:[RLMObjectServerTests authServerURL]
- timeout:30.0
- callbackQueue:dispatch_get_main_queue()
- onCompletion:^(__unused RLMSyncUser *user, NSError *error) {
- XCTAssertNotNil(error);
- XCTAssertTrue([NSThread isMainThread]);
- [ex2 fulfill];
- }];
- [self waitForExpectationsWithTimeout:2.0 handler:nil];
- }
- - (void)testUserExpirationCallback {
- NSString *username = NSStringFromSelector(_cmd);
- RLMSyncCredentials *credentials = [RLMSyncCredentials credentialsWithUsername:username
- password:@"a"
- register:YES];
- RLMSyncUser *user = [self logInUserForCredentials:credentials
- server:[RLMObjectServerTests authServerURL]];
- XCTestExpectation *ex = [self expectationWithDescription:@"callback should fire"];
-
- __weak RLMSyncUser *weakUser = user;
- user.errorHandler = ^(RLMSyncUser *u, NSError *error) {
- XCTAssertEqualObjects(u.identity, weakUser.identity);
-
- XCTAssertEqualObjects(error.domain, RLMSyncAuthErrorDomain);
- XCTAssertEqual(error.code, RLMSyncAuthErrorAccessDeniedOrInvalidPath);
- [ex fulfill];
- };
-
- [self manuallySetRefreshTokenForUser:user value:@"not_a_real_refresh_token"];
-
- __attribute__((objc_precise_lifetime)) RLMRealm *r = [self immediatelyOpenRealmForURL:REALM_URL() user:user];
- [self waitForExpectationsWithTimeout:10.0 handler:nil];
- XCTAssertTrue(user.state == RLMSyncUserStateLoggedOut);
- }
- #pragma mark - Basic Sync
- - (void)testOpenRealmWithAdminToken {
-
-
- RLMSyncCredentials *credentials = [RLMSyncCredentials credentialsWithAccessToken:self.adminToken identity:@"test"];
- XCTAssertNotNil(credentials);
- RLMSyncUser *user = [self logInUserForCredentials:credentials
- server:[RLMObjectServerTests authServerURL]];
- NSURL *url = [NSURL URLWithString:@"realm://127.0.0.1:9080/testSyncWithAdminToken"];
- RLMRealmConfiguration *c = [user configurationWithURL:url fullSynchronization:YES];
- NSError *error = nil;
- RLMRealm *realm = [RLMRealm realmWithConfiguration:c error:&error];
- XCTAssertNil(error);
- XCTAssertTrue(realm.isEmpty);
- }
- - (void)testOpenRealmWithNormalCredentials {
- RLMSyncUser *user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:YES]
- server:[RLMObjectServerTests authServerURL]];
- NSURL *url = REALM_URL();
- RLMRealm *realm = [self openRealmForURL:url user:user];
- XCTAssertTrue(realm.isEmpty);
- }
- - (void)testAddObjects {
- NSURL *url = REALM_URL();
- RLMSyncUser *user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:self.isParent]
- server:[RLMObjectServerTests authServerURL]];
- RLMRealm *realm = [self openRealmForURL:url user:user];
- if (self.isParent) {
- CHECK_COUNT(0, SyncObject, realm);
- RLMRunChildAndWait();
- [self waitForDownloadsForUser:user realms:@[realm] realmURLs:@[url] expectedCounts:@[@3]];
- } else {
-
- [self addSyncObjectsToRealm:realm descriptions:@[@"child-1", @"child-2", @"child-3"]];
- [self waitForUploadsForRealm:realm];
- CHECK_COUNT(3, SyncObject, realm);
- }
- }
- - (void)testDeleteObjects {
- NSURL *url = REALM_URL();
- RLMSyncUser *user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:self.isParent]
- server:[RLMObjectServerTests authServerURL]];
- RLMRealm *realm = [self openRealmForURL:url user:user];
- if (self.isParent) {
-
- [self addSyncObjectsToRealm:realm descriptions:@[@"parent-1", @"parent-2", @"parent-3"]];
- [self waitForUploadsForRealm:realm];
- CHECK_COUNT(3, SyncObject, realm);
- RLMRunChildAndWait();
- [self waitForDownloadsForRealm:realm];
- CHECK_COUNT(0, SyncObject, realm);
- } else {
- [self waitForDownloadsForRealm:realm];
- CHECK_COUNT(3, SyncObject, realm);
- [realm beginWriteTransaction];
- [realm deleteAllObjects];
- [realm commitWriteTransaction];
- [self waitForUploadsForRealm:realm];
- CHECK_COUNT(0, SyncObject, realm);
- }
- }
- #pragma mark - Encryption
- - (void)testEncryptedSyncedRealm {
- NSURL *url = REALM_URL();
- RLMSyncUser *user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:self.isParent]
- server:[RLMObjectServerTests authServerURL]];
- NSData *key = RLMGenerateKey();
- RLMRealm *realm = [self openRealmForURL:url user:user encryptionKey:key
- stopPolicy:RLMSyncStopPolicyAfterChangesUploaded immediatelyBlock:nil];
- if (self.isParent) {
- CHECK_COUNT(0, SyncObject, realm);
- RLMRunChildAndWait();
- [self waitForDownloadsForUser:user realms:@[realm] realmURLs:@[url] expectedCounts:@[@3]];
- } else {
-
- [self addSyncObjectsToRealm:realm descriptions:@[@"child-1", @"child-2", @"child-3"]];
- [self waitForUploadsForRealm:realm];
- CHECK_COUNT(3, SyncObject, realm);
- }
- }
- - (void)testEncryptedSyncedRealmWrongKey {
- NSURL *url = REALM_URL();
- RLMSyncUser *user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:self.isParent]
- server:[RLMObjectServerTests authServerURL]];
- if (self.isParent) {
- NSString *path;
- @autoreleasepool {
- RLMRealm *realm = [self openRealmForURL:url user:user encryptionKey:RLMGenerateKey()
- stopPolicy:RLMSyncStopPolicyImmediately immediatelyBlock:nil];
- path = realm.configuration.pathOnDisk;
- CHECK_COUNT(0, SyncObject, realm);
- RLMRunChildAndWait();
- [self waitForDownloadsForUser:user realms:@[realm] realmURLs:@[url] expectedCounts:@[@3]];
- }
- RLMRealmConfiguration *c = [RLMRealmConfiguration defaultConfiguration];
- c.fileURL = [NSURL fileURLWithPath:path];
- RLMAssertThrowsWithError([RLMRealm realmWithConfiguration:c error:nil],
- @"Unable to open a realm at path",
- RLMErrorFileAccess,
- @"invalid mnemonic");
- c.encryptionKey = RLMGenerateKey();
- RLMAssertThrowsWithError([RLMRealm realmWithConfiguration:c error:nil],
- @"Unable to open a realm at path",
- RLMErrorFileAccess,
- @"Realm file decryption failed");
- } else {
- RLMRealm *realm = [self openRealmForURL:url user:user encryptionKey:RLMGenerateKey()
- stopPolicy:RLMSyncStopPolicyImmediately immediatelyBlock:nil];
- [self addSyncObjectsToRealm:realm descriptions:@[@"child-1", @"child-2", @"child-3"]];
- [self waitForUploadsForRealm:realm];
- CHECK_COUNT(3, SyncObject, realm);
- }
- }
- #pragma mark - Multiple Realm Sync
- - (void)testMultipleRealmsSessions {
- NSURL *urlA = CUSTOM_REALM_URL(@"a");
- NSURL *urlB = CUSTOM_REALM_URL(@"b");
- NSURL *urlC = CUSTOM_REALM_URL(@"c");
- RLMSyncUser *user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:self.isParent]
- server:[RLMObjectServerTests authServerURL]];
-
- __attribute__((objc_precise_lifetime)) RLMRealm *realmealmA = [self openRealmForURL:urlA user:user];
- __attribute__((objc_precise_lifetime)) RLMRealm *realmealmB = [self openRealmForURL:urlB user:user];
- __attribute__((objc_precise_lifetime)) RLMRealm *realmealmC = [self openRealmForURL:urlC user:user];
-
- XCTAssert(user.allSessions.count == 3, @"Expected 3 sessions, but didn't get 3 sessions");
- XCTAssertNotNil([user sessionForURL:urlA], @"Expected to get a session for URL A");
- XCTAssertNotNil([user sessionForURL:urlB], @"Expected to get a session for URL B");
- XCTAssertNotNil([user sessionForURL:urlC], @"Expected to get a session for URL C");
- XCTAssertTrue([user sessionForURL:urlA].state == RLMSyncSessionStateActive, @"Expected active session for URL A");
- XCTAssertTrue([user sessionForURL:urlB].state == RLMSyncSessionStateActive, @"Expected active session for URL B");
- XCTAssertTrue([user sessionForURL:urlC].state == RLMSyncSessionStateActive, @"Expected active session for URL C");
- }
- - (void)testMultipleRealmsAddObjects {
- NSURL *urlA = CUSTOM_REALM_URL(@"a");
- NSURL *urlB = CUSTOM_REALM_URL(@"b");
- NSURL *urlC = CUSTOM_REALM_URL(@"c");
- RLMSyncUser *user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:self.isParent]
- server:[RLMObjectServerTests authServerURL]];
- RLMRealm *realmA = [self openRealmForURL:urlA user:user];
- RLMRealm *realmB = [self openRealmForURL:urlB user:user];
- RLMRealm *realmC = [self openRealmForURL:urlC user:user];
- if (self.isParent) {
- [self waitForDownloadsForRealm:realmA];
- [self waitForDownloadsForRealm:realmB];
- [self waitForDownloadsForRealm:realmC];
- CHECK_COUNT(0, SyncObject, realmA);
- CHECK_COUNT(0, SyncObject, realmB);
- CHECK_COUNT(0, SyncObject, realmC);
- RLMRunChildAndWait();
- [self waitForDownloadsForUser:user
- realms:@[realmA, realmB, realmC]
- realmURLs:@[urlA, urlB, urlC]
- expectedCounts:@[@3, @2, @5]];
- } else {
-
- [self addSyncObjectsToRealm:realmA
- descriptions:@[@"child-A1", @"child-A2", @"child-A3"]];
- [self addSyncObjectsToRealm:realmB
- descriptions:@[@"child-B1", @"child-B2"]];
- [self addSyncObjectsToRealm:realmC
- descriptions:@[@"child-C1", @"child-C2", @"child-C3", @"child-C4", @"child-C5"]];
- [self waitForUploadsForRealm:realmA];
- [self waitForUploadsForRealm:realmB];
- [self waitForUploadsForRealm:realmC];
- CHECK_COUNT(3, SyncObject, realmA);
- CHECK_COUNT(2, SyncObject, realmB);
- CHECK_COUNT(5, SyncObject, realmC);
- }
- }
- - (void)testMultipleRealmsDeleteObjects {
- NSURL *urlA = CUSTOM_REALM_URL(@"a");
- NSURL *urlB = CUSTOM_REALM_URL(@"b");
- NSURL *urlC = CUSTOM_REALM_URL(@"c");
- RLMSyncUser *user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:self.isParent]
- server:[RLMObjectServerTests authServerURL]];
- RLMRealm *realmA = [self openRealmForURL:urlA user:user];
- RLMRealm *realmB = [self openRealmForURL:urlB user:user];
- RLMRealm *realmC = [self openRealmForURL:urlC user:user];
- if (self.isParent) {
- [self waitForDownloadsForRealm:realmA];
- [self waitForDownloadsForRealm:realmB];
- [self waitForDownloadsForRealm:realmC];
-
- [self addSyncObjectsToRealm:realmA
- descriptions:@[@"parent-A1", @"parent-A2", @"parent-A3", @"parent-A4"]];
- [self addSyncObjectsToRealm:realmB
- descriptions:@[@"parent-B1", @"parent-B2", @"parent-B3", @"parent-B4", @"parent-B5"]];
- [self addSyncObjectsToRealm:realmC
- descriptions:@[@"parent-C1", @"parent-C2"]];
- [self waitForUploadsForRealm:realmA];
- [self waitForUploadsForRealm:realmB];
- [self waitForUploadsForRealm:realmC];
- CHECK_COUNT(4, SyncObject, realmA);
- CHECK_COUNT(5, SyncObject, realmB);
- CHECK_COUNT(2, SyncObject, realmC);
- RLMRunChildAndWait();
- [self waitForDownloadsForUser:user
- realms:@[realmA, realmB, realmC]
- realmURLs:@[urlA, urlB, urlC]
- expectedCounts:@[@0, @0, @0]];
- } else {
-
- [self waitForDownloadsForRealm:realmA];
- [self waitForDownloadsForRealm:realmB];
- [self waitForDownloadsForRealm:realmC];
- CHECK_COUNT(4, SyncObject, realmA);
- CHECK_COUNT(5, SyncObject, realmB);
- CHECK_COUNT(2, SyncObject, realmC);
- [realmA beginWriteTransaction];
- [realmA deleteAllObjects];
- [realmA commitWriteTransaction];
- [realmB beginWriteTransaction];
- [realmB deleteAllObjects];
- [realmB commitWriteTransaction];
- [realmC beginWriteTransaction];
- [realmC deleteAllObjects];
- [realmC commitWriteTransaction];
- [self waitForUploadsForRealm:realmA];
- [self waitForUploadsForRealm:realmB];
- [self waitForUploadsForRealm:realmC];
- CHECK_COUNT(0, SyncObject, realmA);
- CHECK_COUNT(0, SyncObject, realmB);
- CHECK_COUNT(0, SyncObject, realmC);
- }
- }
- #pragma mark - Session Lifetime
- - (void)testUploadChangesWhenRealmOutOfScope {
- const NSInteger OBJECT_COUNT = 10000;
- NSURL *url = REALM_URL();
-
- RLMSyncUser *user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:self.isParent]
- server:[RLMObjectServerTests authServerURL]];
- if (self.isParent) {
-
- @autoreleasepool {
- RLMRealm *realm = [self openRealmForURL:url user:user];
- [realm beginWriteTransaction];
- for (NSInteger i=0; i<OBJECT_COUNT; i++) {
- [realm addObject:[[SyncObject alloc] initWithValue:@[[NSString stringWithFormat:@"parent-%@", @(i+1)]]]];
- }
- [realm commitWriteTransaction];
- CHECK_COUNT(OBJECT_COUNT, SyncObject, realm);
- }
-
-
-
-
- sleep(2);
- RLMRunChildAndWait();
- } else {
- RLMRealm *realm = [self openRealmForURL:url user:user];
-
- [self waitForDownloadsForRealm:realm];
- CHECK_COUNT(OBJECT_COUNT, SyncObject, realm);
- }
- }
- #pragma mark - Logging Back In
- - (void)testLogBackInSameRealmUpload {
- NSURL *url = REALM_URL();
-
- RLMSyncUser *user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:self.isParent]
- server:[RLMObjectServerTests authServerURL]];
- RLMRealm *realm = [self openRealmForURL:url user:user];
- if (self.isParent) {
- [self addSyncObjectsToRealm:realm descriptions:@[@"parent-1"]];
- CHECK_COUNT(1, SyncObject, realm);
- [self waitForUploadsForRealm:realm];
-
- [user logOut];
-
- user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:NO]
- server:[RLMObjectServerTests authServerURL]];
- [self addSyncObjectsToRealm:realm descriptions:@[@"parent-2", @"parent-3"]];
- [self waitForUploadsForRealm:realm];
- CHECK_COUNT(3, SyncObject, realm);
- RLMRunChildAndWait();
- } else {
- [self waitForDownloadsForRealm:realm];
- CHECK_COUNT(3, SyncObject, realm);
- }
- }
- - (void)testLogBackInSameRealmDownload {
- NSURL *url = REALM_URL();
-
- RLMSyncUser *user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:self.isParent]
- server:[RLMObjectServerTests authServerURL]];
- RLMRealm *realm = [self openRealmForURL:url user:user];
- if (self.isParent) {
- [self addSyncObjectsToRealm:realm descriptions:@[@"parent-1"]];
- CHECK_COUNT(1, SyncObject, realm);
- [self waitForUploadsForRealm:realm];
-
- [user logOut];
-
- user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:NO]
- server:[RLMObjectServerTests authServerURL]];
- RLMRunChildAndWait();
- [self waitForDownloadsForRealm:realm];
- CHECK_COUNT(3, SyncObject, realm);
- } else {
- [self waitForDownloadsForRealm:realm];
- [self addSyncObjectsToRealm:realm descriptions:@[@"child-1", @"child-2"]];
- [self waitForUploadsForRealm:realm];
- CHECK_COUNT(3, SyncObject, realm);
- }
- }
- - (void)testLogBackInDeferredRealmUpload {
- NSURL *url = REALM_URL();
-
- RLMSyncUser *user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:self.isParent]
- server:[RLMObjectServerTests authServerURL]];
- NSError *error = nil;
- if (self.isParent) {
-
- dispatch_semaphore_t sema = dispatch_semaphore_create(0);
- RLMRealmConfiguration *config = [user configurationWithURL:url fullSynchronization:true];
- [user logOut];
-
- [self primeSyncManagerWithSemaphore:sema];
- RLMRealm *realm = [RLMRealm realmWithConfiguration:config error:&error];
- XCTAssertNil(error, @"Error when opening Realm: %@", error);
- [self addSyncObjectsToRealm:realm descriptions:@[@"parent-1"]];
- CHECK_COUNT(1, SyncObject, realm);
- user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:NO]
- server:[RLMObjectServerTests authServerURL]];
-
- WAIT_FOR_SEMAPHORE(sema, 30);
- [self addSyncObjectsToRealm:realm descriptions:@[@"parent-2", @"parent-3"]];
- [self waitForUploadsForRealm:realm];
- CHECK_COUNT(3, SyncObject, realm);
- RLMRunChildAndWait();
- } else {
- RLMRealm *realm = [self openRealmForURL:url user:user];
- XCTAssertNil(error, @"Error when opening Realm: %@", error);
- [self waitForDownloadsForRealm:realm];
- CHECK_COUNT(3, SyncObject, realm);
- }
- }
- - (void)testLogBackInDeferredRealmDownload {
- NSURL *url = REALM_URL();
-
- RLMSyncUser *user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:self.isParent]
- server:[RLMObjectServerTests authServerURL]];
- NSError *error = nil;
- if (self.isParent) {
- dispatch_semaphore_t sema = dispatch_semaphore_create(0);
- RLMRunChildAndWait();
- RLMRealmConfiguration *config = [user configurationWithURL:url fullSynchronization:true];
- [user logOut];
-
- [self primeSyncManagerWithSemaphore:sema];
- RLMRealm *realm = [RLMRealm realmWithConfiguration:config error:&error];
- XCTAssertNil(error, @"Error when opening Realm: %@", error);
- [self addSyncObjectsToRealm:realm descriptions:@[@"parent-1"]];
- CHECK_COUNT(1, SyncObject, realm);
- user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:NO]
- server:[RLMObjectServerTests authServerURL]];
-
- WAIT_FOR_SEMAPHORE(sema, 30);
- [self waitForDownloadsForUser:user realms:@[realm] realmURLs:@[url] expectedCounts:@[@4]];
- } else {
- RLMRealm *realm = [self openRealmForURL:url user:user];
- XCTAssertNil(error, @"Error when opening Realm: %@", error);
- [self addSyncObjectsToRealm:realm descriptions:@[@"child-1", @"child-2", @"child-3"]];
- [self waitForUploadsForRealm:realm];
- CHECK_COUNT(3, SyncObject, realm);
- }
- }
- - (void)testLogBackInOpenFirstTimePathUpload {
- NSURL *url = REALM_URL();
-
- RLMSyncUser *user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:self.isParent]
- server:[RLMObjectServerTests authServerURL]];
-
- if (self.isParent) {
-
- [user logOut];
-
- user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:NO]
- server:[RLMObjectServerTests authServerURL]];
-
- RLMRealm *realm = [self openRealmForURL:url user:user];
- [self addSyncObjectsToRealm:realm descriptions:@[@"child-1", @"child-2"]];
- [self waitForUploadsForRealm:realm];
- CHECK_COUNT(2, SyncObject, realm);
- RLMRunChildAndWait();
- } else {
- RLMRealm *realm = [self openRealmForURL:url user:user];
-
- [self waitForDownloadsForRealm:realm];
- CHECK_COUNT(2, SyncObject, realm);
- }
- }
- - (void)testLogBackInOpenFirstTimePathDownload {
- NSURL *url = REALM_URL();
-
- RLMSyncUser *user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:self.isParent]
- server:[RLMObjectServerTests authServerURL]];
-
- if (self.isParent) {
-
- [user logOut];
-
- user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:NO]
- server:[RLMObjectServerTests authServerURL]];
-
- RLMRealm *realm = [self openRealmForURL:url user:user];
-
- RLMRunChildAndWait();
- [self waitForDownloadsForRealm:realm];
- CHECK_COUNT(2, SyncObject, realm);
- } else {
- RLMRealm *realm = [self openRealmForURL:url user:user];
-
- [self waitForDownloadsForRealm:realm];
- [self addSyncObjectsToRealm:realm descriptions:@[@"child-1", @"child-2"]];
- [self waitForUploadsForRealm:realm];
- CHECK_COUNT(2, SyncObject, realm);
- }
- }
- - (void)testLogBackInReopenRealmUpload {
- NSURL *url = REALM_URL();
-
- RLMSyncUser *user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:self.isParent]
- server:[RLMObjectServerTests authServerURL]];
-
- RLMRealm *realm = [self openRealmForURL:url user:user];
- if (self.isParent) {
- [self addSyncObjectsToRealm:realm descriptions:@[@"parent-1"]];
- [self waitForUploadsForRealm:realm];
- CHECK_COUNT(1, SyncObject, realm);
-
- [user logOut];
-
- user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:NO]
- server:[RLMObjectServerTests authServerURL]];
-
- realm = [self immediatelyOpenRealmForURL:url user:user];
- [self addSyncObjectsToRealm:realm descriptions:@[@"child-1", @"child-2", @"child-3", @"child-4"]];
- CHECK_COUNT(5, SyncObject, realm);
- [self waitForUploadsForRealm:realm];
- RLMRunChildAndWait();
- } else {
- [self waitForDownloadsForRealm:realm];
- CHECK_COUNT(5, SyncObject, realm);
- }
- }
- - (void)testLogBackInReopenRealmDownload {
- NSURL *url = REALM_URL();
-
- RLMSyncUser *user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:self.isParent]
- server:[RLMObjectServerTests authServerURL]];
-
- RLMRealm *realm = [self openRealmForURL:url user:user];
- if (self.isParent) {
- [self addSyncObjectsToRealm:realm descriptions:@[@"parent-1"]];
- [self waitForUploadsForRealm:realm];
- XCTAssert([SyncObject allObjectsInRealm:realm].count == 1, @"Expected 1 item");
-
- [user logOut];
-
- user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:NO]
- server:[RLMObjectServerTests authServerURL]];
-
- RLMRunChildAndWait();
-
- realm = [self immediatelyOpenRealmForURL:url user:user];
- [self waitForDownloadsForUser:user realms:@[realm] realmURLs:@[url] expectedCounts:@[@5]];
- } else {
-
- [self waitForDownloadsForRealm:realm];
- CHECK_COUNT(1, SyncObject, realm);
- [self addSyncObjectsToRealm:realm descriptions:@[@"child-1", @"child-2", @"child-3", @"child-4"]];
- [self waitForUploadsForRealm:realm];
- CHECK_COUNT(5, SyncObject, realm);
- }
- }
- #pragma mark - Session suspend and resume
- - (void)testSuspendAndResume {
- NSURL *urlA = CUSTOM_REALM_URL(@"a");
- NSURL *urlB = CUSTOM_REALM_URL(@"b");
- RLMSyncUser *user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:self.isParent]
- server:[RLMObjectServerTests authServerURL]];
- RLMRealm *realmA = [self openRealmForURL:urlA user:user];
- RLMRealm *realmB = [self openRealmForURL:urlB user:user];
- if (self.isParent) {
- [self waitForDownloadsForRealm:realmA];
- [self waitForDownloadsForRealm:realmB];
- CHECK_COUNT(0, SyncObject, realmA);
- CHECK_COUNT(0, SyncObject, realmB);
-
- RLMSyncSession *sessionA = [RLMSyncSession sessionForRealm:realmA];
- [sessionA suspend];
- [self addSyncObjectsToRealm:realmA descriptions:@[@"child-A1"]];
- [self addSyncObjectsToRealm:realmB descriptions:@[@"child-B1"]];
- [self waitForUploadsForRealm:realmB];
- RLMRunChildAndWait();
-
-
- [self waitForDownloadsForRealm:realmB];
- CHECK_COUNT(1, SyncObject, realmA);
- CHECK_COUNT(3, SyncObject, realmB);
-
- [sessionA resume];
- [self waitForDownloadsForRealm:realmA];
- CHECK_COUNT(3, SyncObject, realmA);
- } else {
-
- [self waitForDownloadsForRealm:realmA];
- [self waitForDownloadsForRealm:realmB];
- CHECK_COUNT(0, SyncObject, realmA);
- CHECK_COUNT(1, SyncObject, realmB);
- [self addSyncObjectsToRealm:realmA descriptions:@[@"child-A2", @"child-A3"]];
- [self waitForUploadsForRealm:realmA];
- [self addSyncObjectsToRealm:realmB descriptions:@[@"child-B2", @"child-B3"]];
- [self waitForUploadsForRealm:realmB];
- CHECK_COUNT(2, SyncObject, realmA);
- CHECK_COUNT(3, SyncObject, realmB);
- }
- }
- #pragma mark - Client reset
- - (void)testClientReset {
- NSURL *url = REALM_URL();
- NSString *sessionName = NSStringFromSelector(_cmd);
- RLMSyncUser *user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:sessionName
- register:true]
- server:[RLMObjectServerTests authServerURL]];
-
- __attribute__((objc_precise_lifetime)) RLMRealm *realm = [self openRealmForURL:url user:user];
- __block NSError *theError = nil;
- XCTestExpectation *ex = [self expectationWithDescription:@"Waiting for error handler to be called..."];
- [RLMSyncManager sharedManager].errorHandler = ^void(NSError *error, RLMSyncSession *session) {
-
- XCTAssertTrue([[session.realmURL absoluteString] rangeOfString:sessionName].location != NSNotFound);
- theError = error;
- [ex fulfill];
- };
- [user simulateClientResetErrorForSession:url];
- [self waitForExpectationsWithTimeout:10 handler:nil];
- XCTAssertNotNil(theError);
- XCTAssertTrue(theError.code == RLMSyncErrorClientResetError);
- NSString *pathValue = [theError rlmSync_clientResetBackedUpRealmPath];
- XCTAssertNotNil(pathValue);
-
- NSString *recoveryPath = @"io.realm.object-server-recovered-realms/recovered_realm";
- XCTAssertTrue([pathValue rangeOfString:recoveryPath].location != NSNotFound);
- XCTAssertNotNil([theError rlmSync_errorActionToken]);
- }
- - (void)testClientResetManualInitiation {
- NSURL *url = REALM_URL();
- NSString *sessionName = NSStringFromSelector(_cmd);
- RLMSyncUser *user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:sessionName
- register:true]
- server:[RLMObjectServerTests authServerURL]];
- __block NSError *theError = nil;
- @autoreleasepool {
- __attribute__((objc_precise_lifetime)) RLMRealm *realm = [self openRealmForURL:url user:user];
- XCTestExpectation *ex = [self expectationWithDescription:@"Waiting for error handler to be called..."];
- [RLMSyncManager sharedManager].errorHandler = ^void(NSError *error, RLMSyncSession *session) {
-
- XCTAssertTrue([[session.realmURL absoluteString] rangeOfString:sessionName].location != NSNotFound);
- theError = error;
- [ex fulfill];
- };
- [user simulateClientResetErrorForSession:url];
- [self waitForExpectationsWithTimeout:10 handler:nil];
- XCTAssertNotNil(theError);
- }
-
- NSString *pathValue = [theError rlmSync_clientResetBackedUpRealmPath];
- XCTAssertFalse([[NSFileManager defaultManager] fileExistsAtPath:pathValue]);
- [RLMSyncSession immediatelyHandleError:[theError rlmSync_errorActionToken]];
- XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:pathValue]);
- }
- #pragma mark - Progress Notifications
- static const NSInteger NUMBER_OF_BIG_OBJECTS = 2;
- - (void)populateDataForUser:(RLMSyncUser *)user url:(NSURL *)url {
- RLMRealm *realm = [self openRealmForURL:url user:user];
- [realm beginWriteTransaction];
- for (NSInteger i=0; i<NUMBER_OF_BIG_OBJECTS; i++) {
- [realm addObject:[HugeSyncObject object]];
- }
- [realm commitWriteTransaction];
- [self waitForUploadsForRealm:realm];
- CHECK_COUNT(NUMBER_OF_BIG_OBJECTS, HugeSyncObject, realm);
- }
- - (void)testStreamingDownloadNotifier {
- NSURL *url = REALM_URL();
- RLMSyncUser *user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd) register:self.isParent]
- server:[RLMObjectServerTests authServerURL]];
- if (!self.isParent) {
- [self populateDataForUser:user url:url];
- return;
- }
- __block NSInteger callCount = 0;
- __block NSUInteger transferred = 0;
- __block NSUInteger transferrable = 0;
- __block BOOL hasBeenFulfilled = NO;
-
- [self openRealmForURL:url user:user];
- RLMSyncSession *session = [user sessionForURL:url];
- XCTAssertNotNil(session);
- XCTestExpectation *ex = [self expectationWithDescription:@"streaming-download-notifier"];
- id token = [session addProgressNotificationForDirection:RLMSyncProgressDirectionDownload
- mode:RLMSyncProgressModeReportIndefinitely
- block:^(NSUInteger xfr, NSUInteger xfb) {
-
- XCTAssert(xfr >= transferred);
- XCTAssert(xfb >= transferrable);
- transferred = xfr;
- transferrable = xfb;
- callCount++;
- if (transferrable > 0 && transferred >= transferrable && !hasBeenFulfilled) {
- [ex fulfill];
- hasBeenFulfilled = YES;
- }
- }];
-
- RLMRunChildAndWait();
- [self waitForExpectationsWithTimeout:10.0 handler:nil];
- [token invalidate];
-
-
- XCTAssert(callCount > 1);
- XCTAssert(transferred >= transferrable,
- @"Transferred (%@) needs to be greater than or equal to transferrable (%@)",
- @(transferred), @(transferrable));
- }
- - (void)testStreamingUploadNotifier {
- NSURL *url = REALM_URL();
- RLMSyncUser *user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd) register:self.isParent]
- server:[RLMObjectServerTests authServerURL]];
- __block NSInteger callCount = 0;
- __block NSUInteger transferred = 0;
- __block NSUInteger transferrable = 0;
-
- RLMRealm *realm = [self openRealmForURL:url user:user];
-
- RLMSyncSession *session = [user sessionForURL:url];
- XCTAssertNotNil(session);
- XCTestExpectation *ex = [self expectationWithDescription:@"streaming-upload-expectation"];
- auto token = [session addProgressNotificationForDirection:RLMSyncProgressDirectionUpload
- mode:RLMSyncProgressModeReportIndefinitely
- block:^(NSUInteger xfr, NSUInteger xfb) {
-
-
-
- XCTAssert(xfr >= transferred);
- XCTAssert(xfb >= transferrable);
- transferred = xfr;
- transferrable = xfb;
- callCount++;
- if (transferred > 0 && transferred >= transferrable && transferrable > 1000000 * NUMBER_OF_BIG_OBJECTS) {
- [ex fulfill];
- }
- }];
-
- [realm beginWriteTransaction];
- for (NSInteger i=0; i<NUMBER_OF_BIG_OBJECTS; i++) {
- [realm addObject:[HugeSyncObject object]];
- }
- [realm commitWriteTransaction];
-
- [self waitForExpectationsWithTimeout:10.0 handler:nil];
- [token invalidate];
-
-
- XCTAssert(callCount > 1);
- XCTAssert(transferred >= transferrable,
- @"Transferred (%@) needs to be greater than or equal to transferrable (%@)",
- @(transferred), @(transferrable));
- }
- #pragma mark - Download Realm
- - (void)testDownloadRealm {
- const NSInteger NUMBER_OF_BIG_OBJECTS = 2;
- NSURL *url = REALM_URL();
- RLMSyncUser *user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd) register:self.isParent]
- server:[RLMObjectServerTests authServerURL]];
- if (!self.isParent) {
- [self populateDataForUser:user url:url];
- return;
- }
-
- RLMRunChildAndWait();
- XCTestExpectation *ex = [self expectationWithDescription:@"download-realm"];
- RLMRealmConfiguration *c = [user configurationWithURL:url fullSynchronization:true];
- XCTAssertFalse([[NSFileManager defaultManager] fileExistsAtPath:c.pathOnDisk isDirectory:nil]);
- [RLMRealm asyncOpenWithConfiguration:c
- callbackQueue:dispatch_get_main_queue()
- callback:^(RLMRealm * _Nullable realm, NSError * _Nullable error) {
- XCTAssertNil(error);
- CHECK_COUNT(NUMBER_OF_BIG_OBJECTS, HugeSyncObject, realm);
- [ex fulfill];
- }];
- NSUInteger (^fileSize)(NSString *) = ^NSUInteger(NSString *path) {
- NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil];
- if (attributes)
- return [(NSNumber *)attributes[NSFileSize] unsignedLongLongValue];
- return 0;
- };
- XCTAssertNil(RLMGetAnyCachedRealmForPath(c.pathOnDisk.UTF8String));
- [self waitForExpectationsWithTimeout:10.0 handler:nil];
- XCTAssertGreaterThan(fileSize(c.pathOnDisk), 0U);
- XCTAssertNil(RLMGetAnyCachedRealmForPath(c.pathOnDisk.UTF8String));
- }
- - (void)testDownloadAlreadyOpenRealm {
- const NSInteger NUMBER_OF_BIG_OBJECTS = 2;
- NSURL *url = REALM_URL();
-
- RLMSyncUser *user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd) register:self.isParent]
- server:[RLMObjectServerTests authServerURL]];
- if (!self.isParent) {
- [self populateDataForUser:user url:url];
- return;
- }
- XCTestExpectation *ex = [self expectationWithDescription:@"download-realm"];
- RLMRealmConfiguration *c = [user configurationWithURL:url fullSynchronization:true];
- XCTAssertFalse([[NSFileManager defaultManager] fileExistsAtPath:c.pathOnDisk isDirectory:nil]);
- RLMRealm *realm = [RLMRealm realmWithConfiguration:c error:nil];
- CHECK_COUNT(0, HugeSyncObject, realm);
- [realm.syncSession suspend];
-
- RLMRunChildAndWait();
- auto fileSize = ^NSUInteger(NSString *path) {
- NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil];
- return [(NSNumber *)attributes[NSFileSize] unsignedLongLongValue];
- };
- NSUInteger sizeBefore = fileSize(c.pathOnDisk);
- XCTAssertGreaterThan(sizeBefore, 0U);
- XCTAssertNotNil(RLMGetAnyCachedRealmForPath(c.pathOnDisk.UTF8String));
- [RLMRealm asyncOpenWithConfiguration:c
- callbackQueue:dispatch_get_main_queue()
- callback:^(RLMRealm * _Nullable realm, NSError * _Nullable error) {
- XCTAssertNil(error);
- CHECK_COUNT(NUMBER_OF_BIG_OBJECTS, HugeSyncObject, realm);
- [ex fulfill];
- }];
- [realm.syncSession resume];
- [self waitForExpectationsWithTimeout:2.0 handler:nil];
- XCTAssertGreaterThan(fileSize(c.pathOnDisk), sizeBefore);
- XCTAssertNotNil(RLMGetAnyCachedRealmForPath(c.pathOnDisk.UTF8String));
- CHECK_COUNT(NUMBER_OF_BIG_OBJECTS, HugeSyncObject, realm);
- (void)[realm configuration];
- }
- - (void)testDownloadCancelsOnAuthError {
- RLMSyncUser *user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd) register:self.isParent]
- server:[RLMObjectServerTests authServerURL]];
- auto c = [user configurationWithURL:[NSURL URLWithString:@"realm://127.0.0.1:9080/invalid"] fullSynchronization:true];
- auto ex = [self expectationWithDescription:@"async open"];
- [RLMRealm asyncOpenWithConfiguration:c callbackQueue:dispatch_get_main_queue()
- callback:^(RLMRealm *realm, NSError *error) {
- XCTAssertNil(realm);
- XCTAssertNotNil(error);
- [ex fulfill];
- }];
- [self waitForExpectationsWithTimeout:2.0 handler:nil];
- }
- - (void)testCancelDownload {
- NSURL *url = REALM_URL();
- RLMSyncUser *user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd) register:self.isParent]
- server:[RLMObjectServerTests authServerURL]];
- if (!self.isParent) {
- [self populateDataForUser:user url:url];
- return;
- }
-
- RLMRunChildAndWait();
-
-
- RLMSetAsyncOpenQueue(dispatch_queue_create("io.realm.asyncOpen", 0));
- XCTestExpectation *ex = [self expectationWithDescription:@"download-realm"];
- RLMRealmConfiguration *c = [user configurationWithURL:url fullSynchronization:true];
- [RLMRealm asyncOpenWithConfiguration:c
- callbackQueue:dispatch_get_main_queue()
- callback:^(RLMRealm *realm, NSError *error) {
- XCTAssertNil(realm);
- XCTAssertNotNil(error);
- [ex fulfill];
- }];
- [[RLMRealm asyncOpenWithConfiguration:c
- callbackQueue:dispatch_get_main_queue()
- callback:^(RLMRealm *, NSError *) {
- XCTFail(@"Cancelled callback got called");
- }] cancel];
- [self waitForExpectationsWithTimeout:2.0 handler:nil];
- }
- - (void)testAsyncOpenProgressNotifications {
- NSURL *url = REALM_URL();
- RLMSyncUser *user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd) register:self.isParent]
- server:[RLMObjectServerTests authServerURL]];
- if (!self.isParent) {
- [self populateDataForUser:user url:url];
- return;
- }
- RLMRunChildAndWait();
- XCTestExpectation *ex1 = [self expectationWithDescription:@"async open"];
- XCTestExpectation *ex2 = [self expectationWithDescription:@"download progress complete"];
- RLMRealmConfiguration *c = [user configurationWithURL:url fullSynchronization:true];
- auto task = [RLMRealm asyncOpenWithConfiguration:c
- callbackQueue:dispatch_get_main_queue()
- callback:^(RLMRealm *realm, NSError *error) {
- XCTAssertNil(error);
- XCTAssertNotNil(realm);
- [ex1 fulfill];
- }];
- [task addProgressNotificationBlock:^(NSUInteger transferredBytes, NSUInteger transferrableBytes) {
- if (transferrableBytes > 0 && transferredBytes == transferrableBytes) {
- [ex2 fulfill];
- }
- }];
- [self waitForExpectationsWithTimeout:2.0 handler:nil];
- }
- - (void)testAsyncOpenConnectionTimeout {
- NSString *userName = NSStringFromSelector(_cmd);
-
- NSURL *authURL = [NSURL URLWithString:@"http://127.0.0.1:9083"];
- RLMSyncUser *user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:userName register:YES]
- server:authURL];
- RLMRealmConfiguration *c = [user configuration];
- RLMSyncConfiguration *syncConfig = c.syncConfiguration;
- syncConfig.cancelAsyncOpenOnNonFatalErrors = true;
- c.syncConfiguration = syncConfig;
- RLMSyncTimeoutOptions *timeoutOptions = [RLMSyncTimeoutOptions new];
- timeoutOptions.connectTimeout = 1000.0;
- RLMSyncManager.sharedManager.timeoutOptions = timeoutOptions;
- XCTestExpectation *ex = [self expectationWithDescription:@"async open"];
- [RLMRealm asyncOpenWithConfiguration:c
- callbackQueue:dispatch_get_main_queue()
- callback:^(RLMRealm *realm, NSError *error) {
- XCTAssertNotNil(error);
- XCTAssertEqual(error.code, ETIMEDOUT);
- XCTAssertEqual(error.domain, NSPOSIXErrorDomain);
- XCTAssertNil(realm);
- [ex fulfill];
- }];
- [self waitForExpectationsWithTimeout:10.0 handler:nil];
- }
- #pragma mark - Compact on Launch
- - (void)testCompactOnLaunch {
- NSURL *url = REALM_URL();
- RLMSyncUser *user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:YES]
- server:[RLMObjectServerTests authServerURL]];
- NSString *path;
-
-
- @autoreleasepool {
- auto realm = [self openRealmForURL:url user:user];
- [realm beginWriteTransaction];
- [realm addObject:[HugeSyncObject object]];
- [realm commitWriteTransaction];
- [self waitForUploadsForRealm:realm];
- [realm beginWriteTransaction];
- [realm deleteAllObjects];
- [realm commitWriteTransaction];
- [self waitForUploadsForRealm:realm];
- [self waitForDownloadsForRealm:realm];
- path = realm.configuration.pathOnDisk;
- }
- auto fileManager = NSFileManager.defaultManager;
- auto initialSize = [[fileManager attributesOfItemAtPath:path error:nil][NSFileSize] unsignedLongLongValue];
-
-
- auto config = [user configurationWithURL:url fullSynchronization:true];
- __block bool blockCalled = false;
- __block NSUInteger usedSize = 0;
- config.shouldCompactOnLaunch = ^(NSUInteger, NSUInteger used) {
- usedSize = used;
- blockCalled = true;
- return YES;
- };
- @autoreleasepool {
- [RLMRealm realmWithConfiguration:config error:nil];
- }
- XCTAssertTrue(blockCalled);
- auto finalSize = [[fileManager attributesOfItemAtPath:path error:nil][NSFileSize] unsignedLongLongValue];
- XCTAssertLessThan(finalSize, initialSize);
- XCTAssertLessThanOrEqual(finalSize, usedSize + 4096U);
- }
- #pragma mark - Partial sync
- - (void)waitForKeyPath:(NSString *)keyPath object:(id)object value:(id)value {
- [self waitForExpectations:@[[[XCTKVOExpectation alloc] initWithKeyPath:keyPath object:object expectedValue:value]] timeout:20.0];
- }
- - (void)testPartialSync {
-
- NSString *name = NSStringFromSelector(_cmd);
- NSURL *server = [RLMObjectServerTests authServerURL];
-
- @autoreleasepool {
- RLMSyncCredentials *creds = [RLMObjectServerTests basicCredentialsWithName:name register:YES];
- RLMSyncUser *user = [self logInUserForCredentials:creds server:server];
- RLMRealmConfiguration *configuration = [user configuration];
- RLMRealm *realm = [self openRealmWithConfiguration:configuration];
- [realm beginWriteTransaction];
-
-
- [realm addObject:[PartialSyncObjectA objectWithNumber:0 string:@"realm"]];
- [realm addObject:[PartialSyncObjectA objectWithNumber:1 string:@""]];
- [realm addObject:[PartialSyncObjectA objectWithNumber:2 string:@""]];
- [realm addObject:[PartialSyncObjectA objectWithNumber:3 string:@""]];
- [realm addObject:[PartialSyncObjectA objectWithNumber:4 string:@"realm"]];
- [realm addObject:[PartialSyncObjectA objectWithNumber:5 string:@"sync"]];
- [realm addObject:[PartialSyncObjectA objectWithNumber:6 string:@"partial"]];
- [realm addObject:[PartialSyncObjectA objectWithNumber:7 string:@"partial"]];
- [realm addObject:[PartialSyncObjectA objectWithNumber:8 string:@"partial"]];
- [realm addObject:[PartialSyncObjectA objectWithNumber:9 string:@"partial"]];
- [realm addObject:[PartialSyncObjectB objectWithNumber:0 firstString:@"" secondString:@""]];
- [realm addObject:[PartialSyncObjectB objectWithNumber:1 firstString:@"" secondString:@""]];
- [realm addObject:[PartialSyncObjectB objectWithNumber:2 firstString:@"" secondString:@""]];
- [realm addObject:[PartialSyncObjectB objectWithNumber:3 firstString:@"" secondString:@""]];
- [realm addObject:[PartialSyncObjectB objectWithNumber:4 firstString:@"" secondString:@""]];
- [realm addObject:[PartialSyncObjectB objectWithNumber:5 firstString:@"" secondString:@""]];
- [realm addObject:[PartialSyncObjectB objectWithNumber:6 firstString:@"" secondString:@""]];
- [realm addObject:[PartialSyncObjectB objectWithNumber:7 firstString:@"" secondString:@""]];
- [realm addObject:[PartialSyncObjectB objectWithNumber:8 firstString:@"" secondString:@""]];
- [realm addObject:[PartialSyncObjectB objectWithNumber:9 firstString:@"" secondString:@""]];
- [realm commitWriteTransaction];
- [self waitForUploadsForRealm:realm];
- }
-
- @autoreleasepool {
- RLMSyncCredentials *creds = [RLMObjectServerTests basicCredentialsWithName:name register:NO];
- RLMSyncUser *user = [self logInUserForCredentials:creds server:server];
- RLMRealmConfiguration *configuration = [user configuration];
- RLMRealm *realm = [self openRealmWithConfiguration:configuration];
-
- RLMResults *objects = [PartialSyncObjectA objectsInRealm:realm where:@"number > 5"];
- RLMSyncSubscription *subscription = [objects subscribeWithName:@"query"];
-
- [self waitForKeyPath:@"state" object:subscription value:@(RLMSyncSubscriptionStateComplete)];
-
- XCTAssertEqual(objects.count, 4U);
- for (PartialSyncObjectA *object in objects) {
- XCTAssertGreaterThan(object.number, 5);
- XCTAssertEqualObjects(object.string, @"partial");
- }
-
- XCTAssertEqual([PartialSyncObjectA allObjectsInRealm:realm].count, objects.count);
- XCTAssertEqual([PartialSyncObjectB allObjectsInRealm:realm].count, 0u);
-
- RLMResults *objects2 = [PartialSyncObjectA objectsInRealm:realm where:@"number < 5"];
- RLMSyncSubscription *subscription2 = [objects2 subscribeWithName:@"query"];
-
- [self waitForKeyPath:@"state" object:subscription2 value:@(RLMSyncSubscriptionStateError)];
- XCTAssertNotNil(subscription2.error);
-
- [subscription unsubscribe];
- [self waitForKeyPath:@"state" object:subscription value:@(RLMSyncSubscriptionStateInvalidated)];
- }
- }
- - (RLMRealm *)partialRealmWithName:(SEL)sel {
- NSString *name = NSStringFromSelector(sel);
- NSURL *server = [RLMObjectServerTests authServerURL];
- RLMSyncCredentials *creds = [RLMObjectServerTests basicCredentialsWithName:name register:YES];
- RLMSyncUser *user = [self logInUserForCredentials:creds server:server];
- RLMRealmConfiguration *configuration = [user configuration];
- return [self openRealmWithConfiguration:configuration];
- }
- - (void)testAllSubscriptionsChecksThatRealmIsQBS {
- RLMRealm *nonsyncRealm = [RLMRealm defaultRealm];
- RLMAssertThrowsWithReason(nonsyncRealm.subscriptions, @"query-based sync");
- NSString *name = NSStringFromSelector(_cmd);
- NSURL *server = [RLMObjectServerTests authServerURL];
- RLMSyncCredentials *creds = [RLMObjectServerTests basicCredentialsWithName:name register:YES];
- RLMSyncUser *user = [self logInUserForCredentials:creds server:server];
- RLMRealm *fullsyncRealm = [self openRealmWithConfiguration:[user configurationWithURL:[NSURL URLWithString:@"realms://localhost:9443/~/default"] fullSynchronization:YES]];
- RLMAssertThrowsWithReason(fullsyncRealm.subscriptions, @"query-based sync");
- }
- - (void)testAllSubscriptionsReportsNewlyCreatedSubscription {
- RLMRealm *realm = [self partialRealmWithName:_cmd];
- XCTAssertEqual(0U, realm.subscriptions.count);
- RLMSyncSubscription *subscription = [[PartialSyncObjectA objectsInRealm:realm where:@"number > 5"]
- subscribeWithName:@"query"];
-
- XCTAssertEqual(0U, realm.subscriptions.count);
- [self waitForKeyPath:@"state" object:subscription value:@(RLMSyncSubscriptionStateComplete)];
- XCTAssertEqual(1U, realm.subscriptions.count);
- RLMSyncSubscription *subscription2 = realm.subscriptions.firstObject;
- XCTAssertEqualObjects(@"query", subscription2.name);
- XCTAssertEqual(RLMSyncSubscriptionStateComplete, subscription2.state);
- XCTAssertNil(subscription2.error);
- }
- - (void)testAllSubscriptionsDoesNotReportLocalError {
- RLMRealm *realm = [self partialRealmWithName:_cmd];
- RLMSyncSubscription *subscription1 = [[PartialSyncObjectA objectsInRealm:realm where:@"number > 5"]
- subscribeWithName:@"query"];
- [self waitForKeyPath:@"state" object:subscription1 value:@(RLMSyncSubscriptionStateComplete)];
- RLMSyncSubscription *subscription2 = [[PartialSyncObjectA objectsInRealm:realm where:@"number > 6"]
- subscribeWithName:@"query"];
- [self waitForKeyPath:@"state" object:subscription2 value:@(RLMSyncSubscriptionStateError)];
- XCTAssertEqual(1U, realm.subscriptions.count);
- }
- - (void)testAllSubscriptionsReportsServerError {
- RLMRealm *realm = [self partialRealmWithName:_cmd];
- RLMSyncSubscription *subscription = [[PersonObject objectsInRealm:realm where:@"SUBQUERY(parents, $p1, $p1.age < 31 AND SUBQUERY($p1.parents, $p2, $p2.age > 35 AND $p2.name == 'Michael').@count > 0).@count > 0"]
- subscribeWithName:@"query"];
- XCTAssertEqual(0U, realm.subscriptions.count);
- [self waitForKeyPath:@"state" object:subscription value:@(RLMSyncSubscriptionStateError)];
- XCTAssertEqual(1U, realm.subscriptions.count);
- RLMSyncSubscription *subscription2 = realm.subscriptions.lastObject;
- XCTAssertEqualObjects(@"query", subscription2.name);
- XCTAssertEqual(RLMSyncSubscriptionStateError, subscription2.state);
- XCTAssertNotNil(subscription2.error);
- }
- - (void)testUnsubscribeUsingOriginalSubscriptionObservingFetched {
- RLMRealm *realm = [self partialRealmWithName:_cmd];
- RLMSyncSubscription *original = [[PartialSyncObjectA allObjectsInRealm:realm] subscribeWithName:@"query"];
- [self waitForKeyPath:@"state" object:original value:@(RLMSyncSubscriptionStateComplete)];
- XCTAssertEqual(1U, realm.subscriptions.count);
- RLMSyncSubscription *fetched = realm.subscriptions.firstObject;
- [original unsubscribe];
- [self waitForKeyPath:@"state" object:fetched value:@(RLMSyncSubscriptionStateInvalidated)];
- XCTAssertEqual(0U, realm.subscriptions.count);
- XCTAssertEqual(RLMSyncSubscriptionStateInvalidated, original.state);
-
-
-
- realm->_realm->close();
- }
- - (void)testUnsubscribeUsingFetchedSubscriptionObservingFetched {
- RLMRealm *realm = [self partialRealmWithName:_cmd];
- RLMSyncSubscription *original = [[PartialSyncObjectA allObjectsInRealm:realm] subscribeWithName:@"query"];
- [self waitForKeyPath:@"state" object:original value:@(RLMSyncSubscriptionStateComplete)];
- XCTAssertEqual(1U, realm.subscriptions.count);
- RLMSyncSubscription *fetched = realm.subscriptions.firstObject;
- [fetched unsubscribe];
- [self waitForKeyPath:@"state" object:fetched value:@(RLMSyncSubscriptionStateInvalidated)];
- XCTAssertEqual(0U, realm.subscriptions.count);
- XCTAssertEqual(RLMSyncSubscriptionStateInvalidated, original.state);
-
-
-
- realm->_realm->close();
- }
- - (void)testUnsubscribeUsingFetchedSubscriptionObservingOriginal {
- RLMRealm *realm = [self partialRealmWithName:_cmd];
- RLMSyncSubscription *original = [[PartialSyncObjectA allObjectsInRealm:realm] subscribeWithName:@"query"];
- [self waitForKeyPath:@"state" object:original value:@(RLMSyncSubscriptionStateComplete)];
- XCTAssertEqual(1U, realm.subscriptions.count);
- RLMSyncSubscription *fetched = realm.subscriptions.firstObject;
- [fetched unsubscribe];
- [self waitForKeyPath:@"state" object:original value:@(RLMSyncSubscriptionStateInvalidated)];
- XCTAssertEqual(0U, realm.subscriptions.count);
- XCTAssertEqual(RLMSyncSubscriptionStateInvalidated, fetched.state);
- }
- - (void)testSubscriptionWithName {
- RLMRealm *nonsyncRealm = [RLMRealm defaultRealm];
- XCTAssertThrows([nonsyncRealm subscriptionWithName:@"name"]);
- RLMRealm *realm = [self partialRealmWithName:_cmd];
- XCTAssertNil([realm subscriptionWithName:@"query"]);
- RLMSyncSubscription *subscription = [[PartialSyncObjectA allObjectsInRealm:realm] subscribeWithName:@"query"];
- XCTAssertNil([realm subscriptionWithName:@"query"]);
- [self waitForKeyPath:@"state" object:subscription value:@(RLMSyncSubscriptionStateComplete)];
- XCTAssertNotNil([realm subscriptionWithName:@"query"]);
- XCTAssertNil([realm subscriptionWithName:@"query2"]);
- RLMSyncSubscription *subscription2 = [realm subscriptionWithName:@"query"];
- XCTAssertEqualObjects(@"query", subscription2.name);
- XCTAssertEqual(RLMSyncSubscriptionStateComplete, subscription2.state);
- XCTAssertNil(subscription2.error);
- [subscription unsubscribe];
- XCTAssertNotNil([realm subscriptionWithName:@"query"]);
- [self waitForKeyPath:@"state" object:subscription value:@(RLMSyncSubscriptionStateInvalidated)];
- XCTAssertNil([realm subscriptionWithName:@"query"]);
- XCTAssertEqual(RLMSyncSubscriptionStateInvalidated, subscription2.state);
- }
- - (void)testSortAndFilterSubscriptions {
- RLMRealm *realm = [self partialRealmWithName:_cmd];
- NSDate *now = NSDate.date;
- [self waitForKeyPath:@"state" object:[[PartialSyncObjectA allObjectsInRealm:realm] subscribeWithName:@"query 1"]
- value:@(RLMSyncSubscriptionStateComplete)];
- [self waitForKeyPath:@"state" object:[[PartialSyncObjectA allObjectsInRealm:realm] subscribeWithName:@"query 2"]
- value:@(RLMSyncSubscriptionStateComplete)];
- [self waitForKeyPath:@"state" object:[[PartialSyncObjectB allObjectsInRealm:realm] subscribeWithName:@"query 3"]
- value:@(RLMSyncSubscriptionStateComplete)];
- RLMResults *unsupportedQuery = [PersonObject objectsInRealm:realm where:@"SUBQUERY(parents, $p1, $p1.age < 31 AND SUBQUERY($p1.parents, $p2, $p2.age > 35 AND $p2.name == 'Michael').@count > 0).@count > 0"];
- [self waitForKeyPath:@"state" object:[unsupportedQuery subscribeWithName:@"query 4"]
- value:@(RLMSyncSubscriptionStateError)];
- auto subscriptions = realm.subscriptions;
- XCTAssertEqual(4U, subscriptions.count);
- XCTAssertEqual(0U, ([subscriptions objectsWhere:@"name = %@", @"query 0"].count));
- XCTAssertEqualObjects(@"query 1", ([subscriptions objectsWhere:@"name = %@", @"query 1"].firstObject.name));
- XCTAssertEqual(3U, ([subscriptions objectsWhere:@"status = %@", @(RLMSyncSubscriptionStateComplete)].count));
- XCTAssertEqual(1U, ([subscriptions objectsWhere:@"status = %@", @(RLMSyncSubscriptionStateError)].count));
- XCTAssertEqual(4U, ([subscriptions objectsWhere:@"createdAt >= %@", now]).count);
- XCTAssertEqual(0U, ([subscriptions objectsWhere:@"createdAt < %@", now]).count);
- XCTAssertEqual(4U, [subscriptions objectsWhere:@"expiresAt = nil"].count);
- XCTAssertEqual(4U, [subscriptions objectsWhere:@"timeToLive = nil"].count);
- XCTAssertThrows([subscriptions sortedResultsUsingKeyPath:@"name" ascending:NO]);
- XCTAssertThrows([subscriptions sortedResultsUsingDescriptors:@[]]);
- XCTAssertThrows([subscriptions distinctResultsUsingKeyPaths:@[@"name"]]);
- }
- - (void)testIncludeLinkingObjectsErrorHandling {
- RLMRealm *realm = [self partialRealmWithName:_cmd];
- RLMResults *objects = [PersonObject allObjectsInRealm:realm];
- RLMSyncSubscriptionOptions *opt = [RLMSyncSubscriptionOptions new];
- opt.includeLinkingObjectProperties = @[@"nonexistent"];
- RLMAssertThrowsWithReason([objects subscribeWithOptions:opt],
- @"Invalid LinkingObjects inclusion from key path 'nonexistent': property 'PersonObject.nonexistent' does not exist.");
- opt.includeLinkingObjectProperties = @[@"name"];
- RLMAssertThrowsWithReason([objects subscribeWithOptions:opt],
- @"Invalid LinkingObjects inclusion from key path 'name': property 'PersonObject.name' is of unsupported type 'string'.");
- opt.includeLinkingObjectProperties = @[@"children.name"];
- RLMAssertThrowsWithReason([objects subscribeWithOptions:opt],
- @"Invalid LinkingObjects inclusion from key path 'children.name': property 'PersonObject.name' is of unsupported type 'string'.");
- opt.includeLinkingObjectProperties = @[@"children"];
- RLMAssertThrowsWithReason([objects subscribeWithOptions:opt],
- @"Invalid LinkingObjects inclusion from key path 'children': key path must end in a LinkingObjects property and 'PersonObject.children' is of type 'array'.");
- opt.includeLinkingObjectProperties = @[@"children."];
- RLMAssertThrowsWithReason([objects subscribeWithOptions:opt],
- @"Invalid LinkingObjects inclusion from key path 'children.': missing property name.");
- opt.includeLinkingObjectProperties = @[@""];
- RLMAssertThrowsWithReason([objects subscribeWithOptions:opt],
- @"Invalid LinkingObjects inclusion from key path '': missing property name.");
- }
- #pragma mark - Certificate pinning
- - (void)attemptLoginWithUsername:(NSString *)userName callback:(void (^)(RLMSyncUser *, NSError *))callback {
- NSURL *url = [RLMObjectServerTests secureAuthServerURL];
- RLMSyncCredentials *creds = [RLMObjectServerTests basicCredentialsWithName:userName register:YES];
- XCTestExpectation *expectation = [self expectationWithDescription:@"HTTP login"];
- [RLMSyncUser logInWithCredentials:creds authServerURL:url
- onCompletion:^(RLMSyncUser *user, NSError *error) {
- callback(user, error);
- [expectation fulfill];
- }];
- [self waitForExpectationsWithTimeout:4.0 handler:nil];
- }
- - (void)testHTTPSLoginFailsWithoutCertificate {
- [self attemptLoginWithUsername:NSStringFromSelector(_cmd) callback:^(RLMSyncUser *user, NSError *error) {
- XCTAssertNil(user);
- XCTAssertNotNil(error);
- XCTAssertEqualObjects(error.domain, NSURLErrorDomain);
- XCTAssertEqual(error.code, NSURLErrorServerCertificateUntrusted);
- }];
- }
- static NSURL *certificateURL(NSString *filename) {
- return [NSURL fileURLWithPath:[[[@(__FILE__) stringByDeletingLastPathComponent]
- stringByAppendingPathComponent:@"certificates"]
- stringByAppendingPathComponent:filename]];
- }
- - (void)testHTTPSLoginFailsWithIncorrectCertificate {
- RLMSyncManager.sharedManager.pinnedCertificatePaths = @{@"localhost": certificateURL(@"not-localhost.cer")};
- [self attemptLoginWithUsername:NSStringFromSelector(_cmd) callback:^(RLMSyncUser *user, NSError *error) {
- XCTAssertNil(user);
- XCTAssertNotNil(error);
- XCTAssertEqualObjects(error.domain, NSURLErrorDomain);
- XCTAssertEqual(error.code, NSURLErrorServerCertificateUntrusted);
- }];
- }
- - (void)testHTTPSLoginFailsWithInvalidPathToCertificate {
- RLMSyncManager.sharedManager.pinnedCertificatePaths = @{@"localhost": certificateURL(@"nonexistent.pem")};
- [self attemptLoginWithUsername:NSStringFromSelector(_cmd) callback:^(RLMSyncUser *user, NSError *error) {
- XCTAssertNil(user);
- XCTAssertNotNil(error);
- XCTAssertEqualObjects(error.domain, NSCocoaErrorDomain);
- XCTAssertEqual(error.code, NSFileReadNoSuchFileError);
- }];
- }
- - (void)testHTTPSLoginFailsWithDifferentValidCert {
- RLMSyncManager.sharedManager.pinnedCertificatePaths = @{@"localhost": certificateURL(@"localhost-other.cer")};
- [self attemptLoginWithUsername:NSStringFromSelector(_cmd) callback:^(RLMSyncUser *user, NSError *error) {
- XCTAssertNil(user);
- XCTAssertNotNil(error);
- XCTAssertEqualObjects(error.domain, NSURLErrorDomain);
- XCTAssertEqual(error.code, NSURLErrorServerCertificateUntrusted);
- }];
- }
- - (void)testHTTPSLoginFailsWithFileThatIsNotACert {
- RLMSyncManager.sharedManager.pinnedCertificatePaths = @{@"localhost": certificateURL(@"../test-ros-server.js")};
- [self attemptLoginWithUsername:NSStringFromSelector(_cmd) callback:^(RLMSyncUser *user, NSError *error) {
- XCTAssertNil(user);
- XCTAssertNotNil(error);
- XCTAssertEqualObjects(error.domain, NSOSStatusErrorDomain);
- XCTAssertEqual(error.code, errSecUnknownFormat);
- }];
- }
- - (void)testHTTPSLoginDoesNotUseCertificateForDifferentDomain {
- RLMSyncManager.sharedManager.pinnedCertificatePaths = @{@"example.com": certificateURL(@"localhost.cer")};
- [self attemptLoginWithUsername:NSStringFromSelector(_cmd) callback:^(RLMSyncUser *user, NSError *error) {
- XCTAssertNil(user);
- XCTAssertNotNil(error);
- XCTAssertEqualObjects(error.domain, NSURLErrorDomain);
- XCTAssertEqual(error.code, NSURLErrorServerCertificateUntrusted);
- }];
- }
- - (void)testHTTPSLoginSucceedsWithValidSelfSignedCertificate {
- RLMSyncManager.sharedManager.pinnedCertificatePaths = @{@"localhost": certificateURL(@"localhost.cer")};
- [self attemptLoginWithUsername:NSStringFromSelector(_cmd) callback:^(RLMSyncUser *user, NSError *error) {
- XCTAssertNotNil(user);
- XCTAssertNil(error);
- }];
- }
- - (void)testConfigurationFromUserAutomaticallyUsesCert {
- RLMSyncManager.sharedManager.pinnedCertificatePaths = @{@"localhost": certificateURL(@"localhost.cer")};
- __block RLMSyncUser *user;
- [self attemptLoginWithUsername:NSStringFromSelector(_cmd) callback:^(RLMSyncUser *u, NSError *error) {
- XCTAssertNotNil(u);
- XCTAssertNil(error);
- user = u;
- }];
- RLMRealmConfiguration *config = [user configuration];
- XCTAssertEqualObjects(config.syncConfiguration.realmURL.scheme, @"realms");
- XCTAssertEqualObjects(config.syncConfiguration.pinnedCertificateURL, certificateURL(@"localhost.cer"));
-
- auto realm = [self openRealmWithConfiguration:config];
- NSError *error;
- [self waitForUploadsForRealm:realm error:&error];
- XCTAssertNil(error);
- }
- - (void)verifyOpenSucceeds:(RLMRealmConfiguration *)config {
- auto realm = [self openRealmWithConfiguration:config];
- NSError *error;
- [self waitForUploadsForRealm:realm error:&error];
- XCTAssertNil(error);
- }
- - (void)verifyOpenFails:(RLMRealmConfiguration *)config {
- XCTestExpectation *expectation = [self expectationWithDescription:@"wait for error"];
- RLMSyncManager.sharedManager.errorHandler = ^(NSError *error, __unused RLMSyncSession *session) {
- XCTAssertTrue([error.domain isEqualToString:RLMSyncErrorDomain]);
- XCTAssertFalse([[error.userInfo[kRLMSyncUnderlyingErrorKey] domain] isEqualToString:RLMSyncErrorDomain]);
- [expectation fulfill];
- };
- [self openRealmWithConfiguration:config];
- [self waitForExpectationsWithTimeout:20.0 handler:nil];
- }
- - (void)testConfigurationFromInsecureUserAutomaticallyUsesCert {
- RLMSyncManager.sharedManager.pinnedCertificatePaths = @{@"localhost": certificateURL(@"localhost.cer")};
- RLMSyncUser *user = [self logInUserForCredentials:[RLMSyncTestCase basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:YES]
- server:[RLMSyncTestCase authServerURL]];
- RLMRealmConfiguration *config = [user configurationWithURL:[NSURL URLWithString:@"realms://localhost:9443/~/default"]];
- XCTAssertEqualObjects(config.syncConfiguration.realmURL.scheme, @"realms");
- XCTAssertEqualObjects(config.syncConfiguration.pinnedCertificateURL, certificateURL(@"localhost.cer"));
- [self verifyOpenSucceeds:config];
- }
- - (void)testOpenSecureRealmWithNoCert {
- RLMSyncUser *user = [self logInUserForCredentials:[RLMSyncTestCase basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:YES]
- server:[RLMSyncTestCase authServerURL]];
- [self verifyOpenFails:[user configurationWithURL:[NSURL URLWithString:@"realms://localhost:9443/~/default"]]];
- }
- - (void)testOpenSecureRealmWithIncorrectCert {
- RLMSyncManager.sharedManager.pinnedCertificatePaths = @{@"localhost": certificateURL(@"not-localhost.cer")};
- RLMSyncUser *user = [self logInUserForCredentials:[RLMSyncTestCase basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:YES]
- server:[RLMSyncTestCase authServerURL]];
- [self verifyOpenFails:[user configurationWithURL:[NSURL URLWithString:@"realms://localhost:9443/~/default"]]];
- }
- - (void)DISABLE_testOpenSecureRealmWithMissingCertFile {
-
- RLMSyncManager.sharedManager.pinnedCertificatePaths = @{@"localhost": certificateURL(@"nonexistent.pem")};
- RLMSyncUser *user = [self logInUserForCredentials:[RLMSyncTestCase basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:YES]
- server:[RLMSyncTestCase authServerURL]];
- [self verifyOpenFails:[user configurationWithURL:[NSURL URLWithString:@"realms://localhost:9443/~/default"]]];
- }
- #pragma mark - Custom request headers
- - (void)testLoginFailsWithoutCustomHeader {
- XCTestExpectation *expectation = [self expectationWithDescription:@"register user"];
- [RLMSyncUser logInWithCredentials:[RLMSyncTestCase basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:YES]
- authServerURL:[NSURL URLWithString:@"http://127.0.0.1:9081"]
- onCompletion:^(RLMSyncUser *user, NSError *error) {
- XCTAssertNil(user);
- XCTAssertNotNil(error);
- XCTAssertEqualObjects(@400, error.userInfo[@"statusCode"]);
- [expectation fulfill];
- }];
- [self waitForExpectationsWithTimeout:4.0 handler:nil];
- }
- - (void)testLoginUsesCustomHeader {
- RLMSyncManager.sharedManager.customRequestHeaders = @{@"X-Allow-Connection": @"true"};
- RLMSyncUser *user = [self logInUserForCredentials:[RLMSyncTestCase basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:YES]
- server:[NSURL URLWithString:@"http://127.0.0.1:9081"]];
- XCTAssertNotNil(user);
- }
- - (void)testModifyCustomHeadersAfterOpeningRealm {
- RLMSyncManager.sharedManager.customRequestHeaders = @{@"X-Allow-Connection": @"true"};
- RLMSyncUser *user = [self logInUserForCredentials:[RLMSyncTestCase basicCredentialsWithName:NSStringFromSelector(_cmd)
- register:YES]
- server:[NSURL URLWithString:@"http://127.0.0.1:9081"]];
- XCTAssertNotNil(user);
- RLMSyncManager.sharedManager.customRequestHeaders = nil;
- NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"realm://127.0.0.1:9081/~/%@", NSStringFromSelector(_cmd)]];
- auto c = [user configurationWithURL:url fullSynchronization:true];
-
- XCTestExpectation *ex1 = [self expectationWithDescription:@"connection failure"];
- RLMSyncManager.sharedManager.errorHandler = ^(NSError *error, RLMSyncSession *) {
- XCTAssertNotNil(error);
- XCTAssertEqualObjects(@400, [error.userInfo[@"underlying_error"] userInfo][@"statusCode"]);
- [ex1 fulfill];
- };
- RLMRealm *realm = [RLMRealm realmWithConfiguration:c error:nil];
- RLMSyncSession *syncSession = realm.syncSession;
- [self waitForExpectationsWithTimeout:4.0 handler:nil];
- XCTAssertEqual(syncSession.connectionState, RLMSyncConnectionStateDisconnected);
-
- RLMSyncManager.sharedManager.errorHandler = nil;
- auto ex2 = [[XCTKVOExpectation alloc] initWithKeyPath:@"connectionState"
- object:syncSession
- expectedValue:@(RLMSyncConnectionStateConnected)];
- RLMSyncManager.sharedManager.customRequestHeaders = @{@"X-Allow-Connection": @"true"};
- [self waitForExpectations:@[ex2] timeout:4.0];
-
- XCTestExpectation *ex3 = [self expectationWithDescription:@"reconnection failure"];
- RLMSyncManager.sharedManager.errorHandler = ^(NSError *error, RLMSyncSession *) {
- XCTAssertNotNil(error);
- XCTAssertEqualObjects(@400, [error.userInfo[@"underlying_error"] userInfo][@"statusCode"]);
- [ex3 fulfill];
- };
- auto ex4 = [[XCTKVOExpectation alloc] initWithKeyPath:@"connectionState"
- object:syncSession
- expectedValue:@(RLMSyncConnectionStateDisconnected)];
- RLMSyncManager.sharedManager.customRequestHeaders = @{@"X-Other-Header": @"true"};
- [self waitForExpectations:@[ex3, ex4] timeout:4.0];
- }
- #pragma mark - Read Only
- - (RLMSyncUser *)userForTest:(SEL)sel {
- return [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(sel)
- register:self.isParent]
- server:[RLMObjectServerTests authServerURL]];
- }
- - (void)testPartialSyncCannotBeReadOnly {
- RLMSyncUser *user = [self userForTest:_cmd];
- RLMRealmConfiguration *config = [user configurationWithURL:nil fullSynchronization:NO];
- RLMAssertThrowsWithReason(config.readOnly = true,
- @"Read-only mode is not supported for query-based sync.");
- }
- - (void)testOpenSynchronouslyInReadOnlyBeforeRemoteSchemaIsInitialized {
- NSURL *url = REALM_URL();
- RLMSyncUser *user = [self userForTest:_cmd];
- if (self.isParent) {
- RLMRealmConfiguration *config = [user configurationWithURL:url fullSynchronization:YES];
- config.readOnly = true;
- RLMRealm *realm = [RLMRealm realmWithConfiguration:config error:nil];
- CHECK_COUNT(0, SyncObject, realm);
- RLMRunChildAndWait();
- [self waitForDownloadsForUser:user realms:@[realm] realmURLs:@[url] expectedCounts:@[@3]];
- } else {
- RLMRealm *realm = [self openRealmForURL:url user:user];
- [self addSyncObjectsToRealm:realm descriptions:@[@"child-1", @"child-2", @"child-3"]];
- [self waitForUploadsForRealm:realm];
- CHECK_COUNT(3, SyncObject, realm);
- }
- }
- - (void)testAddPropertyToReadOnlyRealmWithExistingLocalCopy {
- NSURL *url = REALM_URL();
- RLMSyncUser *user = [self userForTest:_cmd];
- if (!self.isParent) {
- RLMRealm *realm = [self openRealmForURL:url user:user];
- [self addSyncObjectsToRealm:realm descriptions:@[@"child-1", @"child-2", @"child-3"]];
- [self waitForUploadsForRealm:realm];
- return;
- }
- RLMRunChildAndWait();
- RLMRealmConfiguration *config = [user configurationWithURL:url fullSynchronization:YES];
- config.readOnly = true;
- @autoreleasepool {
- (void)[self asyncOpenRealmWithConfiguration:config];
- }
- RLMObjectSchema *objectSchema = [RLMObjectSchema schemaForObjectClass:SyncObject.class];
- objectSchema.properties = [RLMObjectSchema schemaForObjectClass:HugeSyncObject.class].properties;
- config.customSchema = [[RLMSchema alloc] init];
- config.customSchema.objectSchema = @[objectSchema];
- RLMAssertThrowsWithReason([RLMRealm realmWithConfiguration:config error:nil],
- @"Property 'SyncObject.dataProp' has been added.");
- @autoreleasepool {
- NSError *error = [self asyncOpenErrorWithConfiguration:config];
- XCTAssertNotEqual([error.localizedDescription rangeOfString:@"Property 'SyncObject.dataProp' has been added."].location,
- NSNotFound);
- }
- }
- - (void)testAddPropertyToReadOnlyRealmWithAsyncOpen {
- NSURL *url = REALM_URL();
- RLMSyncUser *user = [self userForTest:_cmd];
- if (!self.isParent) {
- RLMRealm *realm = [self openRealmForURL:url user:user];
- [self addSyncObjectsToRealm:realm descriptions:@[@"child-1", @"child-2", @"child-3"]];
- [self waitForUploadsForRealm:realm];
- return;
- }
- RLMRunChildAndWait();
- RLMRealmConfiguration *config = [user configurationWithURL:url fullSynchronization:YES];
- config.readOnly = true;
- RLMObjectSchema *objectSchema = [RLMObjectSchema schemaForObjectClass:SyncObject.class];
- objectSchema.properties = [RLMObjectSchema schemaForObjectClass:HugeSyncObject.class].properties;
- config.customSchema = [[RLMSchema alloc] init];
- config.customSchema.objectSchema = @[objectSchema];
- @autoreleasepool {
- NSError *error = [self asyncOpenErrorWithConfiguration:config];
- XCTAssertNotEqual([error.localizedDescription rangeOfString:@"Property 'SyncObject.dataProp' has been added."].location,
- NSNotFound);
- }
- }
- @end
|