From 5438f4727a9713100c1e5814774687042acc272c Mon Sep 17 00:00:00 2001 From: Pasin Suriyentrakorn Date: Mon, 30 Mar 2015 18:23:11 -0700 Subject: [PATCH] Fix stop idle replicator not getting change notification - In CBL_Replicator's stop method, post progress changed notification after calling stopped. - Refactor CBLReplication's stop method to just calling stop method on the background replicator. - The rest of the logic including forgetting the replicator and setting _started variable will be done in the updateStatus:error:processed:ofTotal: serverCert: method after getting the progress changed notitification after the replication get stopped. #639 --- Source/API/CBLReplication.m | 5 -- Source/CBL_Replicator.m | 4 +- Unit-Tests/Replication_Tests.m | 86 ++++++++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+), 6 deletions(-) diff --git a/Source/API/CBLReplication.m b/Source/API/CBLReplication.m index e3b49262d..f3683c122 100644 --- a/Source/API/CBLReplication.m +++ b/Source/API/CBLReplication.m @@ -304,13 +304,8 @@ - (void) stop { [self tellReplicatorAndWait:^id(CBL_Replicator * bgReplicator) { // This runs on the server thread: [bgReplicator stop]; - [[NSNotificationCenter defaultCenter] removeObserver: self name: nil - object: _bg_replicator]; return @(YES); }]; - - _started = NO; - [_database forgetReplication: self]; } diff --git a/Source/CBL_Replicator.m b/Source/CBL_Replicator.m index b7a5abe5c..bc2057926 100644 --- a/Source/CBL_Replicator.m +++ b/Source/CBL_Replicator.m @@ -398,8 +398,10 @@ - (void) stop { [self stopRemoteRequests]; [NSObject cancelPreviousPerformRequestsWithTarget: self selector: @selector(retryIfReady) object: nil]; - if (_running && _asyncTaskCount == 0) + if (_running && _asyncTaskCount == 0) { [self stopped]; + [self postProgressChanged]; + } } diff --git a/Unit-Tests/Replication_Tests.m b/Unit-Tests/Replication_Tests.m index 7b8da767e..c136e75b7 100644 --- a/Unit-Tests/Replication_Tests.m +++ b/Unit-Tests/Replication_Tests.m @@ -691,4 +691,90 @@ - (void) test11_ReplicationWithReplacedDatabase { Assert([importDb deleteDatabase:&error], @"Couldn't delete db: %@", error); } +- (void) test12_StopIdlePush { + NSURL* remoteDbURL = [self remoteTestDBURL: kPushThenPullDBName]; + if (!remoteDbURL) + return; + [self eraseRemoteDB: remoteDbURL]; + + // Create a continuous push replicator: + CBLReplication* pusher = [db createPushReplication: remoteDbURL]; + pusher.continuous = YES; + + // Run the replicator: + [self runReplication:pusher expectedChangesCount: 0]; + + // Make sure the replication is now idle: + AssertEq(pusher.status, kCBLReplicationIdle); + + // Setup replication change notification observver: + __block BOOL stopped = NO; + id observer = + [[NSNotificationCenter defaultCenter] addObserverForName: kCBLReplicationChangeNotification + object: pusher + queue: nil + usingBlock: ^(NSNotification *note) { + if (pusher.status == kCBLReplicationStopped) + stopped = YES; + }]; + + // Stop the replicator: + [pusher stop]; + + // Wait to get a notification after the replication is stopped: + NSDate* timeout = [NSDate dateWithTimeIntervalSinceNow: 2.0]; + while (!stopped && timeout.timeIntervalSinceNow > 0.0) { + if (![[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode + beforeDate: [NSDate dateWithTimeIntervalSinceNow: 0.5]]) + break; + } + [[NSNotificationCenter defaultCenter] removeObserver: observer]; + + // Check result: + Assert(stopped); +} + +- (void) test13_StopIdlePullReplication { + NSURL* remoteDbURL = [self remoteTestDBURL: kPushThenPullDBName]; + if (!remoteDbURL) + return; + [self eraseRemoteDB: remoteDbURL]; + + // Create a continuous push replicator: + CBLReplication* puller = [db createPullReplication: remoteDbURL]; + puller.continuous = YES; + + // Run the replicator: + [self runReplication:puller expectedChangesCount: 0]; + + // Make sure the replication is now idle: + AssertEq(puller.status, kCBLReplicationIdle); + + // Setup replication change notification observver: + __block BOOL stopped = NO; + id observer = + [[NSNotificationCenter defaultCenter] addObserverForName: kCBLReplicationChangeNotification + object: puller + queue: nil + usingBlock: ^(NSNotification *note) { + if (puller.status == kCBLReplicationStopped) + stopped = YES; + }]; + + // Stop the replicator: + [puller stop]; + + // Wait to get a notification after the replication is stopped: + NSDate* timeout = [NSDate dateWithTimeIntervalSinceNow: 2.0]; + while (!stopped && timeout.timeIntervalSinceNow > 0.0) { + if (![[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode + beforeDate: [NSDate dateWithTimeIntervalSinceNow: 0.5]]) + break; + } + [[NSNotificationCenter defaultCenter] removeObserver: observer]; + + // Check result: + Assert(stopped); +} + @end