package com.couchbase.lite.testapp.ektorp.tests;
import android.util.Log;
import com.couchbase.lite.Database;
import com.couchbase.lite.ReplicationFilter;
import com.couchbase.lite.SavedRevision;
import com.couchbase.lite.ektorp.CBLiteHttpClient;
import com.couchbase.lite.replicator.Replication;
import com.couchbase.lite.support.HttpClientFactory;
import junit.framework.Assert;
import org.apache.http.HttpException;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.AuthState;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HttpContext;
import org.ektorp.CouchDbConnector;
import org.ektorp.CouchDbInstance;
import org.ektorp.ReplicationCommand;
import org.ektorp.ReplicationStatus;
import org.ektorp.http.HttpClient;
import org.ektorp.impl.StdCouchDbInstance;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class Replicator extends CBLiteEktorpTestCase {
public void testPush() throws IOException {
CountDownLatch doneSignal = new CountDownLatch(1);
HttpClient httpClient = new CBLiteHttpClient(manager);
CouchDbInstance dbInstance = new StdCouchDbInstance(httpClient);
// create a local database
CouchDbConnector dbConnector = dbInstance.createConnector(DEFAULT_TEST_DB, true);
// create 3 objects
TestObject test1 = new TestObject(1, false, "ektorp-1");
TestObject test2 = new TestObject(2, false, "ektorp-2");
TestObject test3 = new TestObject(3, false, "ektorp-3");
// save these objects in the database
dbConnector.create(test1);
dbConnector.create(test2);
dbConnector.create(test3);
// push this database to the test replication server
ReplicationCommand pushCommand = new ReplicationCommand.Builder()
.source(DEFAULT_TEST_DB)
.target(getReplicationURL().toExternalForm())
.continuous(false)
.createTarget(true)
.build();
ReplicationStatus status = dbInstance.replicate(pushCommand);
Replication repl = database.getReplicator(status.getSessionId());
ReplicationChangeListener replicationObserver = new ReplicationChangeListener(doneSignal);
repl.addChangeListener(replicationObserver);
try {
boolean success = doneSignal.await(30, TimeUnit.SECONDS);
assertTrue(success);
} catch (InterruptedException e) {
e.printStackTrace();
}
Assert.assertNotNull(status.getSessionId());
}
public void testFilteredPush() throws IOException {
CountDownLatch doneSignal = new CountDownLatch(1);
// install the filter
database.setFilter("evenFoo", new ReplicationFilter() {
@Override
public boolean filter(SavedRevision revision, Map<String, Object> params) {
Integer foo = (Integer) revision.getProperties().get("foo");
if (foo != null && foo.intValue() % 2 == 0) {
return true;
}
return false;
}
});
HttpClient httpClient = new CBLiteHttpClient(manager);
CouchDbInstance dbInstance = new StdCouchDbInstance(httpClient);
// create a local database
CouchDbConnector dbConnector = dbInstance.createConnector(DEFAULT_TEST_DB, true);
// create 3 objects
TestObject test1 = new TestObject(1, false, "ektorp-1");
TestObject test2 = new TestObject(2, false, "ektorp-2");
TestObject test3 = new TestObject(3, false, "ektorp-3");
// save these objects in the database
dbConnector.create(test1);
dbConnector.create(test2);
dbConnector.create(test3);
// push this database to the test replication server
ReplicationCommand pushCommand = new ReplicationCommand.Builder()
.source(DEFAULT_TEST_DB)
.target(getReplicationURL().toExternalForm())
.continuous(false)
.filter("evenFoo")
.build();
ReplicationStatus status = dbInstance.replicate(pushCommand);
Replication repl = database.getReplicator(status.getSessionId());
ReplicationChangeListener replicationObserver = new ReplicationChangeListener(doneSignal);
repl.addChangeListener(replicationObserver);
try {
boolean success = doneSignal.await(30, TimeUnit.SECONDS);
assertTrue(success);
} catch (InterruptedException e) {
e.printStackTrace();
}
Assert.assertNotNull(status.getSessionId());
}
public void testPull() throws IOException {
CountDownLatch doneSignal = new CountDownLatch(1);
HttpClient httpClient = new CBLiteHttpClient(manager);
CouchDbInstance dbInstance = new StdCouchDbInstance(httpClient);
// create a local database
CouchDbConnector dbConnector = dbInstance.createConnector(DEFAULT_TEST_DB, true);
// push this database to the test replication server
ReplicationCommand pushCommand = new ReplicationCommand.Builder()
.source(getReplicationURL().toExternalForm())
.target(DEFAULT_TEST_DB)
.continuous(false)
.build();
ReplicationStatus status = dbInstance.replicate(pushCommand);
Replication repl = database.getReplicator(status.getSessionId());
ReplicationChangeListener replicationObserver = new ReplicationChangeListener(doneSignal);
repl.addChangeListener(replicationObserver);
try {
boolean success = doneSignal.await(30, TimeUnit.SECONDS);
assertTrue(success);
} catch (InterruptedException e) {
e.printStackTrace();
}
Assert.assertNotNull(status.getSessionId());
}
public void testPullWithObserver() throws IOException {
CountDownLatch doneSignal = new CountDownLatch(1);
HttpClient httpClient = new CBLiteHttpClient(manager);
CouchDbInstance dbInstance = new StdCouchDbInstance(httpClient);
// push this database to the test replication server
ReplicationCommand pushCommand = new ReplicationCommand.Builder()
.source(getReplicationURL().toExternalForm())
.target(DEFAULT_TEST_DB)
.continuous(false)
.build();
ReplicationStatus status = dbInstance.replicate(pushCommand);
Replication repl = database.getReplicator(status.getSessionId());
ReplicationChangeListener replicationObserver = new ReplicationChangeListener(doneSignal);
repl.addChangeListener(replicationObserver);
Assert.assertNotNull(status.getSessionId());
Assert.assertEquals(repl.getSessionID(), status.getSessionId());
try {
boolean success = doneSignal.await(30, TimeUnit.SECONDS);
assertTrue(success);
} catch (InterruptedException e) {
e.printStackTrace();
}
Assert.assertTrue(replicationObserver.isReplicationFinished());
}
public void testPullWithoutCredentialsInURL() throws IOException {
CountDownLatch doneSignal = new CountDownLatch(1);
manager.setDefaultHttpClientFactory(new HttpClientFactory() {
@Override
public org.apache.http.client.HttpClient getHttpClient() {
DefaultHttpClient httpClient = new DefaultHttpClient();
BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
//store whatever credentials we have in the credentials provider
AuthScope authScope = new AuthScope(getReplicationServer(), getReplicationPort());
Credentials authCredentials = new UsernamePasswordCredentials(getReplicationAdminUser(), getReplicationAdminPassword());
credsProvider.setCredentials(authScope, authCredentials);
httpClient.setCredentialsProvider(credsProvider);
//set credentials pre-emptively
HttpRequestInterceptor preemptiveAuth = new HttpRequestInterceptor() {
@Override
public void process(HttpRequest request,
HttpContext context) throws HttpException,
IOException {
AuthState authState = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE);
CredentialsProvider credsProvider = (CredentialsProvider) context.getAttribute(
ClientContext.CREDS_PROVIDER);
HttpHost targetHost = (HttpHost) context.getAttribute(ExecutionContext.HTTP_TARGET_HOST);
if (authState.getAuthScheme() == null) {
AuthScope authScope = new AuthScope(targetHost.getHostName(), targetHost.getPort());
Credentials creds = credsProvider.getCredentials(authScope);
authState.setCredentials(creds);
authState.setAuthScheme(new BasicScheme());
}
}
};
httpClient.addRequestInterceptor(preemptiveAuth, 0);
return httpClient;
}
});
HttpClient httpClient = new CBLiteHttpClient(manager);
CouchDbInstance dbInstance = new StdCouchDbInstance(httpClient);
// create a local database
CouchDbConnector dbConnector = dbInstance.createConnector(DEFAULT_TEST_DB, true);
// push this database to the test replication server
ReplicationCommand pushCommand = new ReplicationCommand.Builder()
.source(getReplicationURLWithoutCredentials().toExternalForm())
.target(DEFAULT_TEST_DB)
.continuous(false)
.build();
ReplicationStatus status = dbInstance.replicate(pushCommand);
Replication repl = database.getReplicator(status.getSessionId());
ReplicationChangeListener replicationObserver = new ReplicationChangeListener(doneSignal);
repl.addChangeListener(replicationObserver);
try {
boolean success = doneSignal.await(30, TimeUnit.SECONDS);
assertTrue(success);
} catch (InterruptedException e) {
e.printStackTrace();
}
Assert.assertNotNull(status.getSessionId());
}
// this test is short-circuited because the underlying feature (replication localdb <-> localdb) doesn't work yet
public void disabledTestPushToLocal() throws Exception, IOException {
Database other = manager.getExistingDatabase(DEFAULT_TEST_DB + "2");
if(other != null) {
other.delete();
}
HttpClient httpClient = new CBLiteHttpClient(manager);
CouchDbInstance dbInstance = new StdCouchDbInstance(httpClient);
// create a local database
CouchDbConnector dbConnector = dbInstance.createConnector(DEFAULT_TEST_DB, true);
// create 3 objects
TestObject test1 = new TestObject(1, false, "ektorp-1");
TestObject test2 = new TestObject(2, false, "ektorp-2");
TestObject test3 = new TestObject(3, false, "ektorp-3");
// save these objects in the database
dbConnector.create(test1);
dbConnector.create(test2);
dbConnector.create(test3);
// push this database to the test replication server
ReplicationCommand pushCommand = new ReplicationCommand.Builder()
.source(DEFAULT_TEST_DB)
.target(DEFAULT_TEST_DB + "2")
.continuous(false)
.createTarget(true)
.build();
ReplicationStatus status = dbInstance.replicate(pushCommand);
try {
Thread.sleep(60*1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Assert.assertNotNull(status.getSessionId());
}
class ReplicationChangeListener implements Replication.ChangeListener {
public boolean replicationFinished = false;
private CountDownLatch doneSignal;
ReplicationChangeListener(CountDownLatch doneSignal) {
super();
this.doneSignal = doneSignal;
}
@Override
public void changed(Replication.ChangeEvent event) {
Log.d(TAG, "ReplicationObserver.update called. observable: " + event.getSource());
Replication replicator = (Replication) event.getSource();
if (!replicator.isRunning()) {
replicationFinished = true;
String msg = String.format("myobserver.update called, set replicationFinished to: %b", replicationFinished);
Log.d(TAG, msg);
doneSignal.countDown();
}
else {
String msg = String.format("myobserver.update called, but replicator still running, so ignore it");
Log.d(TAG, msg);
}
}
public boolean isReplicationFinished() {
return replicationFinished;
}
}
}