package com.couchbase.lite.testapp.ektorp.tests; import android.test.InstrumentationTestCase; import android.util.Base64; import android.util.Log; import com.couchbase.lite.CouchbaseLiteException; import com.couchbase.lite.Database; import com.couchbase.lite.Manager; import com.couchbase.lite.android.AndroidContext; import com.couchbase.lite.internal.Body; import com.couchbase.lite.router.Router; import com.couchbase.lite.router.URLConnection; import com.couchbase.lite.router.URLStreamHandlerFactory; import com.couchbase.lite.support.FileDirUtils; import junit.framework.Assert; import org.codehaus.jackson.map.ObjectMapper; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; // Duplicated from CBLite project as an alternative to setting up a whole new library with // code shared between the tests. Hopefully most of this code can be refactored into the // CBLibrary itself in order to reduce code duplication. public abstract class CBLiteEktorpTestCase extends InstrumentationTestCase { public static final String TAG = "CBLiteEktorpTestCase"; private static boolean initializedUrlHandler = false; protected ObjectMapper mapper = new ObjectMapper(); protected Manager manager = null; protected Database database = null; protected String DEFAULT_TEST_DB = "cblite-test"; @Override protected void setUp() throws Exception { Log.v(TAG, "setUp"); super.setUp(); //for some reason a traditional static initializer causes junit to die if(!initializedUrlHandler) { URLStreamHandlerFactory.registerSelfIgnoreError(); initializedUrlHandler = true; } loadCustomProperties(); startCBLite(); startDatabase(); } protected File getServerPath() { return getInstrumentation().getContext().getFilesDir(); } protected void startCBLite() throws CouchbaseLiteException, IOException { File serverPathFile = getServerPath(); FileDirUtils.deleteRecursive(serverPathFile); serverPathFile.mkdir(); manager = new Manager(new AndroidContext(getInstrumentation().getContext()), Manager.DEFAULT_OPTIONS); } protected void stopCBLite() { if(manager != null) { manager.close(); } } protected void startDatabase() throws CouchbaseLiteException { database = ensureEmptyDatabase(DEFAULT_TEST_DB); boolean status = database.open(); Assert.assertTrue(status); } protected void stopDatabse() { if(database != null) { database.close(); } } protected Database ensureEmptyDatabase(String dbName) throws CouchbaseLiteException { Database db = manager.getExistingDatabase(dbName); if(db != null) { db.delete(); } db = manager.getDatabase(dbName); return db; } protected void loadCustomProperties() throws IOException { Properties systemProperties = System.getProperties(); InputStream mainProperties = getInstrumentation().getContext().getAssets().open("test.properties"); if(mainProperties != null) { systemProperties.load(mainProperties); } try { InputStream localProperties = getInstrumentation().getContext().getAssets().open("local-test.properties"); if(localProperties != null) { systemProperties.load(localProperties); } } catch (IOException e) { Log.w(TAG, "Error trying to read from local-test.properties, does this file exist?"); } } protected String getReplicationProtocol() { return System.getProperty("replicationProtocol"); } protected String getReplicationServer() { return System.getProperty("replicationServer"); } protected int getReplicationPort() { return Integer.parseInt(System.getProperty("replicationPort")); } protected String getReplicationAdminUser() { return System.getProperty("replicationAdminUser"); } protected String getReplicationAdminPassword() { return System.getProperty("replicationAdminPassword"); } protected String getReplicationDatabase() { return System.getProperty("replicationDatabase"); } protected URL getReplicationURL() throws MalformedURLException { if(getReplicationAdminUser() != null && getReplicationAdminUser().trim().length() > 0) { return new URL(String.format("%s://%s:%s@%s:%d/%s", getReplicationProtocol(), getReplicationAdminUser(), getReplicationAdminPassword(), getReplicationServer(), getReplicationPort(), getReplicationDatabase())); } else { return new URL(String.format("%s://%s:%d/%s", getReplicationProtocol(), getReplicationServer(), getReplicationPort(), getReplicationDatabase())); } } protected URL getReplicationURLWithoutCredentials() throws MalformedURLException { return new URL(String.format("%s://%s:%d/%s", getReplicationProtocol(), getReplicationServer(), getReplicationPort(), getReplicationDatabase())); } @Override protected void tearDown() throws Exception { Log.v(TAG, "tearDown"); super.tearDown(); stopDatabse(); stopCBLite(); } protected Map<String,Object> userProperties(Map<String,Object> properties) { Map<String,Object> result = new HashMap<String,Object>(); for (String key : properties.keySet()) { if(!key.startsWith("_")) { result.put(key, properties.get(key)); } } return result; } protected void deleteRemoteDB(URL url) { try { Log.v(TAG, String.format("Deleting %s", url.toExternalForm())); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); String userInfo = url.getUserInfo(); if(userInfo != null) { byte[] authEncBytes = Base64.encode(userInfo.getBytes(), Base64.DEFAULT); conn.setRequestProperty("Authorization", "Basic " + new String(authEncBytes)); } conn.setRequestMethod("DELETE"); conn.connect(); int responseCode = conn.getResponseCode(); Assert.assertTrue(responseCode < 300 || responseCode == 404); } catch (Exception e) { Log.e(TAG, "Exceptiong deleting remote db", e); } } protected URLConnection sendRequest(Manager managerParam, String method, String path, Map<String,String> headers, Object bodyObj) { try { URL url = new URL("cblite://" + path); URLConnection conn = (URLConnection)url.openConnection(); conn.setDoOutput(true); conn.setRequestMethod(method); if(headers != null) { for (String header : headers.keySet()) { conn.setRequestProperty(header, headers.get(header)); } } Map<String, List<String>> allProperties = conn.getRequestProperties(); if(bodyObj != null) { conn.setDoInput(true); ByteArrayInputStream bais = new ByteArrayInputStream(mapper.writeValueAsBytes(bodyObj)); conn.setRequestInputStream(bais); } Router router = new Router(managerParam, conn); router.start(); return conn; } catch (MalformedURLException e) { fail(); } catch(IOException e) { fail(); } return null; } protected Object parseJSONResponse(URLConnection conn) { Object result = null; Body responseBody = conn.getResponseBody(); if(responseBody != null) { byte[] json = responseBody.getJson(); String jsonString = null; if(json != null) { jsonString = new String(json); try { result = mapper.readValue(jsonString, Object.class); } catch (Exception e) { fail(); } } } return result; } protected Object sendBody(Manager managerParam, String method, String path, Object bodyObj, int expectedStatus, Object expectedResult) { URLConnection conn = sendRequest(managerParam, method, path, null, bodyObj); Object result = parseJSONResponse(conn); Log.v(TAG, String.format("%s %s --> %d", method, path, conn.getResponseCode())); Assert.assertEquals(expectedStatus, conn.getResponseCode()); if(expectedResult != null) { Assert.assertEquals(expectedResult, result); } return result; } protected Object send(Manager managerParam, String method, String path, int expectedStatus, Object expectedResult) { return sendBody(managerParam, method, path, null, expectedStatus, expectedResult); } }