Browse files

initial checkin of android tester app

  • Loading branch information...
0 parents commit ab25e3fbffa8701a93d702bc84e5f6d35b9489c4 @mschoch mschoch committed Oct 3, 2011
Showing with 1,282 additions and 0 deletions.
  1. +14 −0 .classpath
  2. +17 −0 .gitignore
  3. +33 −0 .project
  4. +10 −0 AndroidManifest.xml
  5. +80 −0 README.md
  6. +11 −0 default.properties
  7. BIN libs/commons-io-2.0.1.jar
  8. BIN libs/jackson-core-asl-1.8.5.jar
  9. BIN libs/jackson-mapper-asl-1.8.5.jar
  10. BIN libs/org.ektorp-1.2.2-SNAPSHOT.jar
  11. BIN libs/org.ektorp.android-1.2.2-SNAPSHOT.jar
  12. BIN libs/slf4j-api-1.6.1.jar
  13. BIN libs/slf4j-jdk14-1.6.1.jar
  14. +40 −0 proguard.cfg
  15. BIN res/drawable-mdpi/dashboard.png
  16. BIN res/drawable-mdpi/dashboard_inv.png
  17. +7 −0 res/drawable-mdpi/tab_monitor.xml
  18. +7 −0 res/drawable-mdpi/tab_workload.xml
  19. BIN res/drawable-mdpi/tractor.png
  20. BIN res/drawable-mdpi/tractor_inv.png
  21. BIN res/drawable/icon.png
  22. +16 −0 res/layout/main.xml
  23. +9 −0 res/layout/monitor_tab.xml
  24. +11 −0 res/layout/workload_row.xml
  25. +9 −0 res/layout/workload_tab.xml
  26. +4 −0 res/values/strings.xml
  27. +195 −0 src/com/couchbase/androidtester/CouchbaseAndroidTesterActivity.java
  28. +22 −0 src/com/couchbase/androidtester/monitors/CouchbaseMonitor.java
  29. +8 −0 src/com/couchbase/androidtester/monitors/CouchbaseMonitorDisplay.java
  30. +26 −0 src/com/couchbase/androidtester/monitors/CouchbasePassiveMonitor.java
  31. +72 −0 src/com/couchbase/androidtester/monitors/CouchbasePollingMonitor.java
  32. +45 −0 src/com/couchbase/androidtester/monitors/MonitorHelper.java
  33. +65 −0 src/com/couchbase/androidtester/monitors/impl/BatteryLevelMonitor.java
  34. +61 −0 src/com/couchbase/androidtester/monitors/impl/CouchbaseServiceMonitor.java
  35. +26 −0 src/com/couchbase/androidtester/monitors/impl/MemoryMonitor.java
  36. +105 −0 src/com/couchbase/androidtester/widget/MonitorsListAdapter.java
  37. +110 −0 src/com/couchbase/androidtester/widget/WorkloadsListAdapter.java
  38. +94 −0 src/com/couchbase/androidtester/workloads/CouchbaseWorkload.java
  39. +10 −0 src/com/couchbase/androidtester/workloads/CouchbaseWorkloadRunner.java
  40. +44 −0 src/com/couchbase/androidtester/workloads/WorkloadHelper.java
  41. +77 −0 src/com/couchbase/androidtester/workloads/impl/CRUDDocuments.java
  42. +54 −0 src/com/couchbase/androidtester/workloads/impl/CreateDocuments.java
14 .classpath
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="src" path="gen"/>
+ <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
+ <classpathentry kind="lib" path="libs/commons-io-2.0.1.jar"/>
+ <classpathentry kind="lib" path="libs/jackson-core-asl-1.8.5.jar"/>
+ <classpathentry kind="lib" path="libs/jackson-mapper-asl-1.8.5.jar"/>
+ <classpathentry kind="lib" path="libs/org.ektorp-1.2.2-SNAPSHOT.jar"/>
+ <classpathentry kind="lib" path="libs/org.ektorp.android-1.2.2-SNAPSHOT.jar"/>
+ <classpathentry kind="lib" path="libs/slf4j-api-1.6.1.jar"/>
+ <classpathentry kind="lib" path="libs/slf4j-jdk14-1.6.1.jar"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
17 .gitignore
@@ -0,0 +1,17 @@
+# built application files
+*.apk
+*.ap_
+
+# files for the dex VM
+*.dex
+
+# Java class files
+*.class
+
+# generated files
+bin/
+gen/
+
+# Local configuration file (sdk path, etc)
+local.properties
+build.properties
33 .project
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>CouchbaseAndroidTester</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>com.android.ide.eclipse.adt.ApkBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>com.android.ide.eclipse.adt.AndroidNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
10 AndroidManifest.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.couchbase.androidtester" android:versionCode="1" android:versionName="1.0">
+ <uses-sdk android:minSdkVersion="7"/>
+
+ <application android:icon="@drawable/icon" android:label="@string/app_name">
+ <activity android:name=".CouchbaseAndroidTesterActivity" android:label="@string/app_name" android:screenOrientation="portrait" android:configChanges="keyboardHidden|orientation">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity></application></manifest>
80 README.md
@@ -0,0 +1,80 @@
+# Couchbase Android Tester
+
+## Getting Started
+
+This project requires the latest version of Couchbase Mobile for Android. This is the only
+dependency not included in the project source tree. Please follow the instructions from
+http://www.couchbase.org/get/couchbase-mobile-for-android/current to get and install the latest
+version of Couchbase Mobile for Android.
+
+## Adding your own workloads
+
+Workloads are built by creating a class that extends the CouchbaseWorkload class. The
+CouchbaseWorkload class is abstract and requires you implement one method performWork(). In
+performWork() you are to perform the entire workload.
+
+### Registering the workload class
+
+To have your workload class show up in the UI, you must register it in WorkloadHelper.java.
+
+### Customizing the name displayed in the UI
+
+To customize the name displayed in the UI, override the getName() method of CouchbaseWorkload.
+
+### Displaying workload progress in the UI
+
+To show the progress of the workload in the UI, add a constructor to your workload class and
+initialize the following variables.
+
+<pre>
+ indeterminate = false;
+ total = //some integer representing the total number of steps
+</pre>
+
+Then, as your workload performs work, update the progress variable accordingly:
+
+<pre>
+ progress++;
+</pre>
+
+### Making sure its possible to stop the workload
+
+To ensure your workload can be stopped when requested by the user, your workload should
+periodically check the status of task.isCancelled(). If this returns true, your performWork()
+method should return as soon as possible.
+
+## Adding your own performance monitors
+
+Performance monitors are built by implementing the CouchbaseMonitor interface. Two convenience
+classes are available depending on the type of monitor you are building. You can extend
+CouchbasePassiveMonitor for building a monitor that can operate without a thread of execution.
+Or you can extend CouchbasePollingMonitor for building a monitor that will periodically poll
+conditions.
+
+It is important to note that the architecture is such that a single performance monitor can
+return multiple measures. This is useful for supporting operations where polling a single
+API periodically is expensive, but yields multiple measures. In this case a single Monitor
+implementation should manage all the measures (see the Memory Monitor example).
+
+### Setting up the monitor
+
+If the monitor requires any set up, the start() method can be overridden.
+
+### Passive Monitors
+
+Passive Monitors should call monitorDisplay.valueChanged() whenever they have determined that
+the value has changed. Then they simply must respond to the currentMeasures() method returning
+a List of Strings describing the current measures. (see the Battery Level Monitor example)
+
+### Polling Monitors
+
+Polling Monitors should implement getMonitorValues() which will be called periodically to poll
+the system for the measures supported by this monitor. (see the Memory Monitor example)
+
+### Registering the monitor class
+
+To have your monitor class show up in the UI, you must register it in MonitorHelper.java.
+
+## Attribution
+
+This project uses icons from http://glyphish.com/ under the Creative Commons Attribution license.
11 default.properties
@@ -0,0 +1,11 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "build.properties", and override values to adapt the script to your
+# project structure.
+
+# Project target.
+target=android-7
BIN libs/commons-io-2.0.1.jar
Binary file not shown.
BIN libs/jackson-core-asl-1.8.5.jar
Binary file not shown.
BIN libs/jackson-mapper-asl-1.8.5.jar
Binary file not shown.
BIN libs/org.ektorp-1.2.2-SNAPSHOT.jar
Binary file not shown.
BIN libs/org.ektorp.android-1.2.2-SNAPSHOT.jar
Binary file not shown.
BIN libs/slf4j-api-1.6.1.jar
Binary file not shown.
BIN libs/slf4j-jdk14-1.6.1.jar
Binary file not shown.
40 proguard.cfg
@@ -0,0 +1,40 @@
+-optimizationpasses 5
+-dontusemixedcaseclassnames
+-dontskipnonpubliclibraryclasses
+-dontpreverify
+-verbose
+-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
+
+-keep public class * extends android.app.Activity
+-keep public class * extends android.app.Application
+-keep public class * extends android.app.Service
+-keep public class * extends android.content.BroadcastReceiver
+-keep public class * extends android.content.ContentProvider
+-keep public class * extends android.app.backup.BackupAgentHelper
+-keep public class * extends android.preference.Preference
+-keep public class com.android.vending.licensing.ILicensingService
+
+-keepclasseswithmembernames class * {
+ native <methods>;
+}
+
+-keepclasseswithmembers class * {
+ public <init>(android.content.Context, android.util.AttributeSet);
+}
+
+-keepclasseswithmembers class * {
+ public <init>(android.content.Context, android.util.AttributeSet, int);
+}
+
+-keepclassmembers class * extends android.app.Activity {
+ public void *(android.view.View);
+}
+
+-keepclassmembers enum * {
+ public static **[] values();
+ public static ** valueOf(java.lang.String);
+}
+
+-keep class * implements android.os.Parcelable {
+ public static final android.os.Parcelable$Creator *;
+}
BIN res/drawable-mdpi/dashboard.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN res/drawable-mdpi/dashboard_inv.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 res/drawable-mdpi/tab_monitor.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector
+ xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/dashboard"
+ android:state_selected="true" />
+ <item android:drawable="@drawable/dashboard_inv" />
+</selector>
7 res/drawable-mdpi/tab_workload.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector
+ xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/tractor"
+ android:state_selected="true" />
+ <item android:drawable="@drawable/tractor_inv" />
+</selector>
BIN res/drawable-mdpi/tractor.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN res/drawable-mdpi/tractor_inv.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN res/drawable/icon.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 res/layout/main.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ >
+ <TabHost android:id="@+id/tabhost" android:layout_width="fill_parent" android:layout_height="fill_parent">
+ <LinearLayout android:id="@+id/linearLayout1" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical">
+ <TabWidget android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@android:id/tabs"></TabWidget>
+ <FrameLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:id="@android:id/tabcontent">
+ <include android:layout_width="fill_parent" android:layout_height="fill_parent" android:id="@+id/tab1" layout="@layout/monitor_tab" />
+ <include android:layout_width="fill_parent" android:layout_height="fill_parent" android:id="@+id/tab2" layout="@layout/workload_tab" />
+ </FrameLayout>
+ </LinearLayout>
+ </TabHost>
+</LinearLayout>
9 res/layout/monitor_tab.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+ <ExpandableListView android:id="@+id/monitorListView" android:layout_height="wrap_content" android:layout_width="fill_parent"></ExpandableListView>
+
+</LinearLayout>
11 res/layout/workload_row.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent" android:orientation="horizontal">
+ <TextView android:id="@+id/workloadTextView" android:text="TextView" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_width="wrap_content" android:textSize="40px"></TextView>
+ <Button android:text="Start" android:id="@+id/workloadStartButton" android:layout_height="wrap_content" android:layout_toLeftOf="@+id/workloadStopButton" android:layout_width="wrap_content" android:textSize="40px"></Button>
+ <Button android:layout_height="wrap_content" android:id="@+id/workloadStopButton" android:text="Stop" android:layout_alignParentRight="true" android:layout_width="wrap_content" android:textSize="40px"></Button>
+ <ProgressBar style="?android:attr/progressBarStyleHorizontal" android:id="@+id/workloadProgressBar" android:layout_height="wrap_content" android:layout_below="@+id/workloadStartButton" android:layout_alignParentLeft="true" android:layout_width="fill_parent"></ProgressBar>
+
+</RelativeLayout>
9 res/layout/workload_tab.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+ <ListView android:layout_height="wrap_content" android:id="@+id/workloadListView" android:layout_width="fill_parent"></ListView>
+
+</LinearLayout>
4 res/values/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="app_name">Couchbase Tester</string>
+</resources>
195 src/com/couchbase/androidtester/CouchbaseAndroidTesterActivity.java
@@ -0,0 +1,195 @@
+package com.couchbase.androidtester;
+
+import java.util.List;
+
+import org.ektorp.CouchDbInstance;
+import org.ektorp.android.http.AndroidHttpClient;
+import org.ektorp.http.HttpClient;
+import org.ektorp.impl.StdCouchDbInstance;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.ProgressDialog;
+import android.content.ServiceConnection;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.ExpandableListView;
+import android.widget.ListView;
+import android.widget.TabHost;
+
+import com.couchbase.android.CouchbaseMobile;
+import com.couchbase.android.ICouchbaseDelegate;
+import com.couchbase.androidtester.monitors.CouchbaseMonitor;
+import com.couchbase.androidtester.monitors.MonitorHelper;
+import com.couchbase.androidtester.widget.MonitorsListAdapter;
+import com.couchbase.androidtester.widget.WorkloadsListAdapter;
+import com.couchbase.androidtester.workloads.CouchbaseWorkload;
+import com.couchbase.androidtester.workloads.WorkloadHelper;
+
+public class CouchbaseAndroidTesterActivity extends Activity {
+
+ public static final String TAG = "CouchbaseTester";
+
+ /**
+ * List of monitors
+ */
+ List<CouchbaseMonitor> monitors;
+
+ /**
+ * Expandable List View Adapter for monitors
+ */
+ private MonitorsListAdapter monitorsListAdapter;
+
+ /**
+ * Expandable List View for monitors
+ */
+ private ExpandableListView monitorsListView;
+
+ /**
+ * List of workloads
+ */
+ private List<CouchbaseWorkload> workloads;
+
+ /**
+ * List View Adapter for workloads
+ */
+ private WorkloadsListAdapter workloadsListAdapter;
+
+ /**
+ * List View for workloads
+ */
+ private ListView workloadsListView;
+
+ /**
+ * ServiceConnection reference to Couch
+ */
+ private ServiceConnection couchServiceConnection;
+
+ /**
+ * CouchDbIntsance of the embedded Couch
+ */
+ private CouchDbInstance couchDbInstance;
+
+ /**
+ * Startup Progress Dialog
+ */
+ private ProgressDialog startupDialog;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main);
+
+ Resources res = getResources();
+
+ TabHost tabs = (TabHost)findViewById(R.id.tabhost);
+
+ tabs.setup();
+
+ TabHost.TabSpec spec1 = tabs.newTabSpec("tag1");
+ spec1.setContent(R.id.tab1);
+ spec1.setIndicator("Monitors", res.getDrawable(R.drawable.tab_monitor));
+ tabs.addTab(spec1);
+
+ TabHost.TabSpec spec2 = tabs.newTabSpec("tag2");
+ spec2.setContent(R.id.tab2);
+ spec2.setIndicator("Workloads", res.getDrawable(R.drawable.tab_workload));
+ tabs.addTab(spec2);
+
+ startupDialog = new ProgressDialog(this);
+ startupDialog.setCancelable(false);
+ startupDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
+ startupDialog.setTitle("Starting Couchbase");
+ startupDialog.show();
+
+ startCouch();
+
+ //now load the rest of the UI
+
+ monitors = MonitorHelper.loadMonitors();
+ for (CouchbaseMonitor monitor : monitors) {
+ monitor.setContext(this);
+ }
+
+ monitorsListAdapter = new MonitorsListAdapter(this, monitors);
+ monitorsListView = (ExpandableListView)findViewById(R.id.monitorListView);
+ monitorsListView.setAdapter(monitorsListAdapter);
+
+ //default all monitor groups to be expanded
+ for(int i=0; i < monitorsListAdapter.getGroupCount(); i++) {
+ monitorsListView.expandGroup(i);
+ }
+
+ workloads = WorkloadHelper.loadWorkloads();
+
+ workloadsListAdapter = new WorkloadsListAdapter(this, workloads);
+ workloadsListView = (ListView)findViewById(R.id.workloadListView);
+ workloadsListView.setAdapter(workloadsListAdapter);
+
+ }
+
+ @Override
+ protected void onDestroy() {
+ unbindService(couchServiceConnection);
+ super.onDestroy();
+ }
+
+ protected void startCouch() {
+ CouchbaseMobile couch = new CouchbaseMobile(getBaseContext(), mDelegate);
+ couchServiceConnection = couch.startCouchbase();
+ }
+
+ private final ICouchbaseDelegate mDelegate = new ICouchbaseDelegate() {
+ @Override
+ public void couchbaseStarted(String host, int port) {
+
+ Log.v(TAG, "Couchbase has started");
+ HttpClient httpClient = new AndroidHttpClient.Builder().host(host).port(port).build();
+ couchDbInstance = new StdCouchDbInstance(httpClient);
+
+ //iterate through all the workloads and give them reference to Couch
+ for (CouchbaseWorkload workload : workloads) {
+ workload.setCouchDbInstance(couchDbInstance);
+ }
+
+ //remove the progress dialog
+ if(startupDialog != null) {
+ startupDialog.hide();
+ }
+
+ };
+
+ @Override
+ public void exit(String error) {
+ }
+ };
+
+ /**
+ * Register the About menu item
+ */
+ public boolean onCreateOptionsMenu(Menu menu) {
+ menu.add(Menu.NONE, 0, 0, "About");
+ return super.onCreateOptionsMenu(menu);
+ }
+
+ /**
+ * Show the About dialog
+ */
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case 0:
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle("About CouchbaseAndroidTester")
+ .setMessage("Icons by http://glyphish.com/ used under a Creative Commons Attribution license.")
+ .setCancelable(true);
+ AlertDialog alert = builder.create();
+ alert.show();
+ return true;
+ }
+ return false;
+ }
+
+}
22 src/com/couchbase/androidtester/monitors/CouchbaseMonitor.java
@@ -0,0 +1,22 @@
+package com.couchbase.androidtester.monitors;
+
+import java.util.List;
+
+
+import android.content.Context;
+
+public interface CouchbaseMonitor {
+
+ void setCouchbaseMonitorDisplay(CouchbaseMonitorDisplay monitorDisplay);
+
+ void setContext(Context context);
+
+ void start();
+
+ void stop();
+
+ String getName();
+
+ List<String> currentMeasures();
+
+}
8 src/com/couchbase/androidtester/monitors/CouchbaseMonitorDisplay.java
@@ -0,0 +1,8 @@
+package com.couchbase.androidtester.monitors;
+
+
+public interface CouchbaseMonitorDisplay {
+
+ void valueChanged();
+
+}
26 src/com/couchbase/androidtester/monitors/CouchbasePassiveMonitor.java
@@ -0,0 +1,26 @@
+package com.couchbase.androidtester.monitors;
+
+
+import android.content.Context;
+
+public abstract class CouchbasePassiveMonitor implements CouchbaseMonitor {
+
+ protected CouchbaseMonitorDisplay monitorDisplay;
+ protected Context context;
+
+ @Override
+ public void setCouchbaseMonitorDisplay(
+ CouchbaseMonitorDisplay monitorDisplay) {
+ this.monitorDisplay = monitorDisplay;
+ }
+
+ @Override
+ public void setContext(Context context) {
+ this.context = context;
+ }
+
+ public String getName() {
+ return this.getClass().getName();
+ }
+
+}
72 src/com/couchbase/androidtester/monitors/CouchbasePollingMonitor.java
@@ -0,0 +1,72 @@
+package com.couchbase.androidtester.monitors;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+import android.content.Context;
+import android.os.AsyncTask;
+
+public abstract class CouchbasePollingMonitor extends AsyncTask<Void, String, Void> implements CouchbaseMonitor {
+
+ public static final int POLL_INTERVAL = 1000;
+ protected CouchbaseMonitorDisplay monitorDisplay;
+ protected Context context;
+ protected List<String> currentMeasures = new ArrayList<String>();
+
+ @Override
+ protected Void doInBackground(Void... params) {
+ while(!isCancelled()) {
+ String[] monitorValues = getMonitorValues();
+ publishProgress(monitorValues);
+ try {
+ Thread.sleep(POLL_INTERVAL);
+ } catch (InterruptedException e) {
+ cancel(false);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ protected void onProgressUpdate(String... values) {
+ currentMeasures = new ArrayList<String>();
+ for (String measure : values) {
+ currentMeasures.add(measure);
+ }
+ monitorDisplay.valueChanged();
+ }
+
+ @Override
+ public void setCouchbaseMonitorDisplay(
+ CouchbaseMonitorDisplay monitorDisplay) {
+ this.monitorDisplay = monitorDisplay;
+ }
+
+ @Override
+ public void setContext(Context context) {
+ this.context = context;
+ }
+
+ public String getName() {
+ return this.getClass().getName();
+ }
+
+ @Override
+ public List<String> currentMeasures() {
+ return currentMeasures;
+ }
+
+ @Override
+ public void start() {
+ this.execute();
+ }
+
+ @Override
+ public void stop() {
+ this.cancel(true);
+ }
+
+ public abstract String[] getMonitorValues();
+
+}
45 src/com/couchbase/androidtester/monitors/MonitorHelper.java
@@ -0,0 +1,45 @@
+package com.couchbase.androidtester.monitors;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.util.Log;
+
+import com.couchbase.androidtester.CouchbaseAndroidTesterActivity;
+
+public class MonitorHelper {
+
+ /**
+ * List of monitor classes
+ */
+ private static List<String> getMonitorClassNames() {
+ //eventually replace this with something scanning the apk for a certain subpackage
+ ArrayList<String> result = new ArrayList<String>();
+ result.add("com.couchbase.androidtester.monitors.impl.CouchbaseServiceMonitor");
+ result.add("com.couchbase.androidtester.monitors.impl.BatteryLevelMonitor");
+ result.add("com.couchbase.androidtester.monitors.impl.MemoryMonitor");
+ return result;
+ }
+
+ /**
+ * Return a list of instantiated CouchbaseMonitor objects
+ * @return the list
+ */
+ public static ArrayList<CouchbaseMonitor> loadMonitors() {
+ ArrayList<CouchbaseMonitor> monitors = new ArrayList<CouchbaseMonitor>();
+
+ List<String> allMonitorClasses = getMonitorClassNames();
+ for (String monitorClassName : allMonitorClasses) {
+ try {
+ Class<?> monitorClass = MonitorHelper.class.getClassLoader().loadClass(monitorClassName);
+ CouchbaseMonitor cm = (CouchbaseMonitor)monitorClass.newInstance();
+ monitors.add(cm);
+ } catch (Exception e) {
+ Log.e(CouchbaseAndroidTesterActivity.TAG, "Exception loading monitors", e);
+ }
+ }
+
+ return monitors;
+ }
+
+}
65 src/com/couchbase/androidtester/monitors/impl/BatteryLevelMonitor.java
@@ -0,0 +1,65 @@
+package com.couchbase.androidtester.monitors.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.BatteryManager;
+
+import com.couchbase.androidtester.monitors.CouchbasePassiveMonitor;
+
+public class BatteryLevelMonitor extends CouchbasePassiveMonitor {
+
+ private String batteryLevelMessage = "Unknown";
+ private String pluggedMessage = "Unknown";
+
+ @Override
+ public void start() {
+ context.registerReceiver(batteryReceiver, new IntentFilter(
+ Intent.ACTION_BATTERY_CHANGED));
+ }
+
+ @Override
+ public void stop() {
+ context.unregisterReceiver(batteryReceiver);
+ }
+
+ private BroadcastReceiver batteryReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
+ batteryLevelMessage = "" + level + "%";
+
+ int plugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
+ switch(plugged) {
+ case 0:
+ pluggedMessage = "On Battery";
+ break;
+ case BatteryManager.BATTERY_PLUGGED_AC:
+ pluggedMessage = "Plugged AC";
+ break;
+ case BatteryManager.BATTERY_PLUGGED_USB:
+ pluggedMessage = "Plugged USB";
+ break;
+ }
+
+ monitorDisplay.valueChanged();
+ }
+ };
+
+ public String getName() {
+ return "Battery Level";
+ };
+
+ @Override
+ public List<String> currentMeasures() {
+ ArrayList<String> result = new ArrayList<String>();
+ result.add(batteryLevelMessage);
+ result.add(pluggedMessage);
+ return result;
+ }
+
+}
61 src/com/couchbase/androidtester/monitors/impl/CouchbaseServiceMonitor.java
@@ -0,0 +1,61 @@
+package com.couchbase.androidtester.monitors.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+
+import com.couchbase.android.Intents.CouchbaseError;
+import com.couchbase.android.Intents.CouchbaseStarted;
+import com.couchbase.androidtester.monitors.CouchbasePassiveMonitor;
+
+public class CouchbaseServiceMonitor extends CouchbasePassiveMonitor {
+
+ private static String currentValue = "Not Running";
+
+ @Override
+ public void start() {
+ context.registerReceiver(couchbaseReceiver, new IntentFilter(
+ CouchbaseStarted.ACTION));
+ context.registerReceiver(couchbaseReceiver, new IntentFilter(
+ CouchbaseError.ACTION));
+ }
+
+ @Override
+ public void stop() {
+ context.unregisterReceiver(couchbaseReceiver);
+ }
+
+ private final BroadcastReceiver couchbaseReceiver = new BroadcastReceiver() {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if(CouchbaseStarted.ACTION.equals(intent.getAction())) {
+ String host = CouchbaseStarted.getHost(intent);
+ int port = CouchbaseStarted.getPort(intent);
+ currentValue = "Listening on " + host + ":" + port;
+ monitorDisplay.valueChanged();
+ }
+ else if(CouchbaseError.ACTION.equals(intent.getAction())) {
+ String message = CouchbaseError.getMessage(intent);
+ currentValue = "Error: " + message;
+ monitorDisplay.valueChanged();
+ }
+ }
+ };
+
+ public String getName() {
+ return "Couchbase";
+ };
+
+ @Override
+ public List<String> currentMeasures() {
+ ArrayList<String> result = new ArrayList<String>();
+ result.add(currentValue);
+ return result;
+ }
+
+}
26 src/com/couchbase/androidtester/monitors/impl/MemoryMonitor.java
@@ -0,0 +1,26 @@
+package com.couchbase.androidtester.monitors.impl;
+
+import android.os.Debug;
+
+import com.couchbase.androidtester.monitors.CouchbasePollingMonitor;
+
+public class MemoryMonitor extends CouchbasePollingMonitor {
+
+ @Override
+ public String[] getMonitorValues() {
+ Debug.MemoryInfo memoryInfo = new Debug.MemoryInfo();
+ Debug.getMemoryInfo(memoryInfo);
+ float totalPrivateDirty = memoryInfo.getTotalPrivateDirty()/1024f;
+ float totalPSS = memoryInfo.getTotalPss()/1024f;
+ float totalSharedDirty = memoryInfo.getTotalSharedDirty()/1024f;
+
+ String[] result = { "Total PSS " + String.format("%.2f", totalPSS) + "MB", "Total Private Dirty " + String.format("%.2f", totalPrivateDirty) + "MB", "Total Shared Dirty " + String.format("%.2f", totalSharedDirty) + "MB" };
+ return result;
+ }
+
+ @Override
+ public String getName() {
+ return "Memory";
+ }
+
+}
105 src/com/couchbase/androidtester/widget/MonitorsListAdapter.java
@@ -0,0 +1,105 @@
+package com.couchbase.androidtester.widget;
+
+import java.util.List;
+
+import android.content.Context;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AbsListView;
+import android.widget.BaseExpandableListAdapter;
+import android.widget.TextView;
+
+import com.couchbase.androidtester.monitors.CouchbaseMonitor;
+import com.couchbase.androidtester.monitors.CouchbaseMonitorDisplay;
+
+public class MonitorsListAdapter extends BaseExpandableListAdapter implements CouchbaseMonitorDisplay {
+
+ protected Context context;
+ protected List<CouchbaseMonitor> monitors;
+
+ public MonitorsListAdapter(Context context, List<CouchbaseMonitor> monitors) {
+ this.context = context;
+ this.monitors = monitors;
+ //set self as monitor display and start
+ for (CouchbaseMonitor couchbaseMonitor : monitors) {
+ couchbaseMonitor.setCouchbaseMonitorDisplay(this);
+ couchbaseMonitor.start();
+ }
+ }
+
+ public Object getChild(int groupPosition, int childPosition) {
+ CouchbaseMonitor monitor = monitors.get(groupPosition);
+ List<String> measures = monitor.currentMeasures();
+ return measures.get(childPosition);
+ }
+
+ public long getChildId(int groupPosition, int childPosition) {
+ return childPosition;
+ }
+
+ public int getChildrenCount(int groupPosition) {
+ CouchbaseMonitor monitor = monitors.get(groupPosition);
+ List<String> measures = monitor.currentMeasures();
+ return measures.size();
+ }
+
+ public TextView getGenericView() {
+ // Layout parameters for the ExpandableListView
+ AbsListView.LayoutParams lp = new AbsListView.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT, 64);
+
+ TextView textView = new TextView(context);
+ textView.setLayoutParams(lp);
+ // Center the text vertically
+ textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
+ // Set the text starting position
+ textView.setPadding(64, 0, 0, 0);
+ return textView;
+ }
+
+ public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
+ View convertView, ViewGroup parent) {
+
+ TextView textView = getGenericView();
+ textView.setText(getChild(groupPosition, childPosition).toString());
+ return textView;
+
+ }
+
+ public Object getGroup(int groupPosition) {
+ CouchbaseMonitor monitor = monitors.get(groupPosition);
+ return monitor.getName();
+ }
+
+ public int getGroupCount() {
+ return monitors.size();
+ }
+
+ public long getGroupId(int groupPosition) {
+ return groupPosition;
+ }
+
+ public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
+ ViewGroup parent) {
+ TextView textView = getGenericView();
+ textView.setText(getGroup(groupPosition).toString());
+ return textView;
+ }
+
+ public boolean isChildSelectable(int groupPosition, int childPosition) {
+ return true;
+ }
+
+ public boolean hasStableIds() {
+ return true;
+ }
+
+ //Couchbase Monitory Display Interface Method
+
+ @Override
+ public void valueChanged() {
+ notifyDataSetChanged();
+ }
+
+}
110 src/com/couchbase/androidtester/widget/WorkloadsListAdapter.java
@@ -0,0 +1,110 @@
+package com.couchbase.androidtester.widget;
+
+import java.util.List;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import com.couchbase.androidtester.R;
+import com.couchbase.androidtester.workloads.CouchbaseWorkload;
+import com.couchbase.androidtester.workloads.CouchbaseWorkloadRunner;
+
+public class WorkloadsListAdapter extends ArrayAdapter<CouchbaseWorkload> implements OnClickListener, CouchbaseWorkloadRunner {
+
+ private Context context;
+
+ public WorkloadsListAdapter(Context context, List<CouchbaseWorkload> workloads) {
+ super(context, 0, workloads);
+ this.context = context;
+
+ //set self as the workload runner
+ for (CouchbaseWorkload couchbaseWorkload : workloads) {
+ couchbaseWorkload.setCouchbaseWorkloadRunner(this);
+ }
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ View v = convertView;
+ if (v == null) {
+ LayoutInflater vi = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ v = vi.inflate(R.layout.workload_row, null);
+ }
+
+ CouchbaseWorkload workload = getItem(position);
+ if(workload != null) {
+ //label
+ TextView workloadTextView = (TextView)v.findViewById(R.id.workloadTextView);
+ workloadTextView.setText(workload.getName());
+
+ //start button
+ Button workloadStartButton = (Button)v.findViewById(R.id.workloadStartButton);
+ workloadStartButton.setOnClickListener(this);
+ workloadStartButton.setTag(position);
+ workloadStartButton.setEnabled(!workload.isRunning());
+
+ //stop button
+ Button workloadStopButton = (Button)v.findViewById(R.id.workloadStopButton);
+ workloadStopButton.setOnClickListener(this);
+ workloadStopButton.setTag(position);
+ workloadStopButton.setEnabled(workload.isRunning());
+
+
+ //progress bar
+ ProgressBar progressBar = (ProgressBar)v.findViewById(R.id.workloadProgressBar);
+ if(workload.isRunning()) {
+ if(!workload.isIndeterminate()) {
+ progressBar.setProgress(workload.getProgress());
+ progressBar.setMax(workload.getTotal());
+ }
+ else {
+ progressBar.setProgress(0);
+ }
+ }
+ else {
+ progressBar.setProgress(0);
+ }
+ }
+
+ return v;
+ }
+
+ //On Click Listener Interface Methods
+ public void onClick(View v) {
+ if(v.getId() == R.id.workloadStartButton) {
+ int position = (Integer)v.getTag();
+ CouchbaseWorkload workload = getItem(position);
+ workload.start();
+ //trigger update of buttons
+ notifyDataSetChanged();
+ }
+ else if(v.getId() == R.id.workloadStopButton){
+ int position = (Integer)v.getTag();
+ CouchbaseWorkload workload = getItem(position);
+ workload.stop();
+ //trigger update of buttons
+ notifyDataSetChanged();
+ }
+ }
+
+ //Couchbase Workload Runner Interface Methods
+ @Override
+ public void workloadReportsFinish(CouchbaseWorkload workload, String finishMessage) {
+ notifyDataSetChanged();
+ };
+
+ @Override
+ public void workloadReportsProgress(CouchbaseWorkload workload,
+ String progressMessage) {
+
+ notifyDataSetChanged();
+ }
+
+}
94 src/com/couchbase/androidtester/workloads/CouchbaseWorkload.java
@@ -0,0 +1,94 @@
+package com.couchbase.androidtester.workloads;
+
+import org.ektorp.CouchDbInstance;
+
+
+import android.os.AsyncTask;
+
+public abstract class CouchbaseWorkload {
+
+ protected CouchbaseWorkloadRunner workloadRunner;
+ protected CouchDbInstance couchDbInstance;
+ protected CouchbaseWorkloadTask task = null;
+ protected int progress = 0;
+ protected int total = 100;
+ protected boolean indeterminate = true;
+
+ public void setCouchbaseWorkloadRunner(CouchbaseWorkloadRunner workloadRunner) {
+ this.workloadRunner = workloadRunner;
+ }
+
+ public void setCouchDbInstance(CouchDbInstance couchDbInstance) {
+ this.couchDbInstance = couchDbInstance;
+ }
+
+ public String getName() {
+ return this.getClass().getName();
+ }
+
+ public void start() {
+ if(task == null) {
+ task = new CouchbaseWorkloadTask();
+ task.execute();
+ }
+ else {
+ throw new IllegalStateException("Workload is already running");
+ }
+ }
+
+ public void stop() {
+ if(task != null) {
+ task.cancel(true);
+ task = null;
+ }
+ else {
+ throw new IllegalStateException("Workload is not running");
+ }
+ }
+
+ public boolean isRunning() {
+ return (task != null);
+ }
+
+ public int getProgress() {
+ return progress;
+ }
+
+ public int getTotal() {
+ return total;
+ }
+
+ public boolean isIndeterminate() {
+ return indeterminate;
+ }
+
+ protected abstract String performWork();
+
+
+ public class CouchbaseWorkloadTask extends AsyncTask<Void, String, String> {
+
+
+ @Override
+ protected String doInBackground(Void... params) {
+ return performWork();
+ }
+
+ @Override
+ protected void onProgressUpdate(String... progressMessages) {
+ for (String progressMessage : progressMessages) {
+ workloadRunner.workloadReportsProgress(CouchbaseWorkload.this, progressMessage);
+ }
+ }
+
+ @Override
+ protected void onPostExecute(String finishMessage) {
+ workloadRunner.workloadReportsFinish(CouchbaseWorkload.this, finishMessage);
+ task = null;
+ }
+
+ public void publishWorkProgress(String... values) {
+ publishProgress(values);
+ }
+ }
+
+}
10 src/com/couchbase/androidtester/workloads/CouchbaseWorkloadRunner.java
@@ -0,0 +1,10 @@
+package com.couchbase.androidtester.workloads;
+
+
+public interface CouchbaseWorkloadRunner {
+
+ public void workloadReportsProgress(CouchbaseWorkload workload, String progressMessage);
+
+ public void workloadReportsFinish(CouchbaseWorkload workload, String finishMessage);
+
+}
44 src/com/couchbase/androidtester/workloads/WorkloadHelper.java
@@ -0,0 +1,44 @@
+package com.couchbase.androidtester.workloads;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.util.Log;
+
+import com.couchbase.androidtester.CouchbaseAndroidTesterActivity;
+
+public class WorkloadHelper {
+
+ /**
+ * List of workload classes
+ */
+ private static List<String> getWorkloadClassNames() {
+ //eventually replace this with something scanning the apk for a certain subpackage
+ ArrayList<String> result = new ArrayList<String>();
+ result.add("com.couchbase.androidtester.workloads.impl.CreateDocuments");
+ result.add("com.couchbase.androidtester.workloads.impl.CRUDDocuments");
+ return result;
+ }
+
+ /**
+ * Return a list of instantiated CouchbaseWorkload objects
+ * @return the list
+ */
+ public static ArrayList<CouchbaseWorkload> loadWorkloads() {
+ ArrayList<CouchbaseWorkload> workloads = new ArrayList<CouchbaseWorkload>();
+
+ List<String> allWorkloadClasses = getWorkloadClassNames();
+ for (String workloadClassName : allWorkloadClasses) {
+ try {
+ Class<?> workloadClass = WorkloadHelper.class.getClassLoader().loadClass(workloadClassName);
+ CouchbaseWorkload cw = (CouchbaseWorkload)workloadClass.newInstance();
+ workloads.add(cw);
+ } catch (Exception e) {
+ Log.e(CouchbaseAndroidTesterActivity.TAG, "Exception loading monitors", e);
+ }
+ }
+
+ return workloads;
+ }
+
+}
77 src/com/couchbase/androidtester/workloads/impl/CRUDDocuments.java
@@ -0,0 +1,77 @@
+package com.couchbase.androidtester.workloads.impl;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.ektorp.CouchDbConnector;
+
+import android.util.Log;
+
+import com.couchbase.androidtester.CouchbaseAndroidTesterActivity;
+import com.couchbase.androidtester.workloads.CouchbaseWorkload;
+
+public class CRUDDocuments extends CouchbaseWorkload {
+
+ private static int numberOfDocuments = 1000;
+
+ public CRUDDocuments() {
+ indeterminate = false;
+ total = 4 * numberOfDocuments;
+ }
+
+ @Override
+ protected String performWork() {
+ CouchDbConnector couchDbConnector = couchDbInstance.createConnector("workload", true);
+
+ int documentsCreated = 0;
+ while(!task.isCancelled() && (documentsCreated < numberOfDocuments)) {
+
+ //create
+ HashMap<String, String> document = documentTemplate();
+ couchDbConnector.create(document);
+ documentsCreated++;
+ progress++;
+ task.publishWorkProgress("Created Document " + documentsCreated);
+
+ String documentId = document.get("_id");
+ Log.v(CouchbaseAndroidTesterActivity.TAG, "Document created got id " + documentId);
+
+ //read
+ @SuppressWarnings("unchecked")
+ Map<String, Object> documentRead = couchDbConnector.get(Map.class, documentId);
+ progress++;
+
+ //update
+ documentRead.put("updated", "true");
+ couchDbConnector.update(documentRead);
+ progress++;
+
+ //delete
+ couchDbConnector.delete(documentRead);
+ progress++;
+ }
+
+ String resultMessage = "" + documentsCreated + " documents";
+
+ if(task.isCancelled()) {
+ resultMessage = "Cancelled CRUD after " + resultMessage;
+ }
+ else {
+ resultMessage = "Finished CRUD " + resultMessage;
+ }
+ progress = 0;
+ return resultMessage;
+ }
+
+ protected HashMap<String, String> documentTemplate() {
+ HashMap<String, String> result = new HashMap<String, String>();
+ result.put("type", "sample");
+ return result;
+ }
+
+ @Override
+ public String getName() {
+ return "CRUD 1000 Documents";
+ }
+
+}
54 src/com/couchbase/androidtester/workloads/impl/CreateDocuments.java
@@ -0,0 +1,54 @@
+package com.couchbase.androidtester.workloads.impl;
+
+import java.util.HashMap;
+
+import org.ektorp.CouchDbConnector;
+
+import com.couchbase.androidtester.workloads.CouchbaseWorkload;
+
+public class CreateDocuments extends CouchbaseWorkload {
+
+ private static int numberOfDocuments = 1000;
+
+ public CreateDocuments() {
+ indeterminate = false;
+ total = numberOfDocuments;
+ }
+
+ @Override
+ protected String performWork() {
+
+ CouchDbConnector couchDbConnector = couchDbInstance.createConnector("workload", true);
+
+ int documentsCreated = 0;
+ while(!task.isCancelled() && (documentsCreated < numberOfDocuments)) {
+ couchDbConnector.create(documentTemplate());
+ documentsCreated++;
+ progress++;
+ task.publishWorkProgress("Created Document " + documentsCreated);
+ }
+
+ String resultMessage = "" + documentsCreated + " documents";
+
+ if(task.isCancelled()) {
+ resultMessage = "Cancelled after creating " + resultMessage;
+ }
+ else {
+ resultMessage = "Finished creating " + resultMessage;
+ }
+ progress = 0;
+ return resultMessage;
+ }
+
+ protected HashMap<String, String> documentTemplate() {
+ HashMap<String, String> result = new HashMap<String, String>();
+ result.put("type", "sample");
+ return result;
+ }
+
+ @Override
+ public String getName() {
+ return "Create 1000 Documents";
+ }
+
+}

0 comments on commit ab25e3f

Please sign in to comment.