TBR: website: Automated tests for DataFlow and DataModel
code snippets.
Change-Id: Ib528bf1f6d5d21f19f9f9feeec86effda7fe5b57
diff --git a/Makefile b/Makefile
index 1cfaceb..9a28af5 100644
--- a/Makefile
+++ b/Makefile
@@ -104,7 +104,9 @@
tutJavaFortune = tutorials/java/fortune
syncbaseAndroidQuickstart = syncbase/quickstart
-syncbaseAndroidFirstApp = syncbase/first-app
+syncbaseAndroidFirstApp = syncbase/first-app
+syncbaseAndroidDataModel = syncbase/guides/data-model
+syncbaseAndroidDataFlow = syncbase/guides/data-flow
# Scripts that 'complete' the named tutorials, creating all relevant files
# (code, credentials, etc.) but skipping ephemeral steps like starting servers,
@@ -384,7 +386,9 @@
depsOneBigSyncbaseAndroidTest = \
content/$(syncbaseAndroidQuickstart).md \
- content/$(syncbaseAndroidFirstApp).md
+ content/$(syncbaseAndroidFirstApp).md \
+ content/$(syncbaseAndroidDataModel).md \
+ content/$(syncbaseAndroidDataFlow).md
.PHONY: test
test: test-site test-tutorials-core test-tutorials-java test-syncbase-android
diff --git a/content/syncbase/guides/data-flow.md b/content/syncbase/guides/data-flow.md
index 92715ed..0851d6e 100644
--- a/content/syncbase/guides/data-flow.md
+++ b/content/syncbase/guides/data-flow.md
@@ -5,6 +5,30 @@
toc: true
= yaml =
+{{# helpers.hidden }}
+<!-- @setupEnvironment @test -->
+```
+export PROJECT_DIR=$(mktemp -d "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX")
+cp -r $JIRI_ROOT/website/tools/android_project_stubs/example/* $PROJECT_DIR
+cat - <<EOF >> $PROJECT_DIR/app/build.gradle
+dependencies {
+ compile 'io.v:syncbase:0.1.4'
+}
+EOF
+cat - <<EOF > $PROJECT_DIR/app/src/main/java/io/v/syncbase/example/DataFlow.java
+package io.v.syncbase.example;
+import io.v.syncbase.*;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+public class DataFlow {
+ Database db;
+ class Task {}
+ void main() {
+EOF
+```
+{{/ helpers.hidden }}
+
# Introduction
Syncbase API is designed to encourage writing reactive applications where the app
@@ -34,38 +58,53 @@
from. UI actions such as adding new task or deleting one simply do a `put` or
`delete` on the corresponding collection.
-```Java
+<!-- @addWatchHandler @test -->
+```
+cat - <<EOF >> $PROJECT_DIR/app/src/main/java/io/v/syncbase/example/DataFlow.java
db.addWatchChangeHandler(new Database.WatchChangeHandler() {
- @Override
- public void onInitialState(Iterator<WatchChange> values) {
+ @Override
+ public void onInitialState(Iterator<WatchChange> values) {
- // onInitialState is called with all of existing data in Syncbase.
- // Although the value type is WatchChange, since this is existing
- // data, there will not be any values with ChangeType == DELETE_CHANGE
- while(values.hasNext()) {
- updateState(values.next());
- }
-
- // Trigger UI update
+ // onInitialState is called with all of existing data in Syncbase.
+ // Although the value type is WatchChange, since this is existing
+ // data, there will not be any values with ChangeType == DELETE_CHANGE
+ while (values.hasNext()) {
+ updateState(values.next());
}
- @Override
- public void onChangeBatch(Iterator<WatchChange> changes) {
+ // Trigger UI update
+ }
- // onChangeBatch is called whenever changes are made to the data.
- // Changes that are part of the same batch are presented together,
- // otherwise changes iterator may only contain a single change.
- while(changes.hasNext()) {
- updateState(changes.next());
- }
+ @Override
+ public void onChangeBatch(Iterator<WatchChange> changes) {
- // Trigger UI update
+ // onChangeBatch is called whenever changes are made to the data.
+ // Changes that are part of the same batch are presented together,
+ // otherwise changes iterator may only contain a single change.
+ while (changes.hasNext()) {
+ updateState(changes.next());
}
-});
+ // Trigger UI update
+ }
+}, new Database.AddWatchChangeHandlerOptions());
+EOF
+```
-// Modeling our in-memory state as a map of Todolist-Id to a map of (Task-Id, Task)
+{{# helpers.hidden }}
+<!-- @closeMainFunction @test -->
+```
+cat - <<EOF >> $PROJECT_DIR/app/src/main/java/io/v/syncbase/example/DataFlow.java
+ }
+EOF
+```
+{{/ helpers.hidden }}
+
+Modeling our in-memory state as a map of Todolist-Id to a map of (Task-Id, Task)
+<!-- @updateState @test -->
+```
+cat - <<EOF >> $PROJECT_DIR/app/src/main/java/io/v/syncbase/example/DataFlow.java
HashMap<String, Map<String, Task>> state = new HashMap<String, Map<String, Task>>();
// Update the state based on the changes.
@@ -74,21 +113,21 @@
String collectionId = change.getCollectionId().encode();
String rowKey = change.getRowKey();
- switch (change.getChangeType()) {
- case ChangeType.PUT_CHANGE:
- if(!state.containsKey(collectionId)) {
- state.put(collectionId, new HashMap<String, Task>());
- }
- Task rowValue = change.getValue(Task.class);
- state.get(collectionId).put(rowKey, rowValue);
- break;
+ if(change.getChangeType() == WatchChange.ChangeType.PUT) {
- case ChangeType.DELETE_CHANGE:
- state.get(collectionId).remove(rowKey);
- break;
+ if(!state.containsKey(collectionId)) {
+ state.put(collectionId, new HashMap<String, Task>());
+ }
+ Task rowValue = (Task)change.getValue();
+ state.get(collectionId).put(rowKey, rowValue);
+
+ } else if(change.getChangeType() == WatchChange.ChangeType.DELETE) {
+
+ state.get(collectionId).remove(rowKey);
+
}
}
-
+EOF
```
{{# helpers.info }}
@@ -105,4 +144,14 @@
* Syncbase's Watch method is designed to help build reactive applications.
* Watch surfaces both local and synced data changes.
* We recommend using the Watch method to keep an up-to-date in-memory state that
-the UI renders from.
\ No newline at end of file
+the UI renders from.
+
+{{# helpers.hidden }}
+<!-- @compileSnippets_mayTakeMinues @test -->
+```
+cat - <<EOF >> $PROJECT_DIR/app/src/main/java/io/v/syncbase/example/DataFlow.java
+}
+EOF
+cd $PROJECT_DIR && ./gradlew assembleRelease
+```
+{{/ helpers.hidden }}
\ No newline at end of file
diff --git a/content/syncbase/guides/data-model.md b/content/syncbase/guides/data-model.md
index 5287909..a2aad2a 100644
--- a/content/syncbase/guides/data-model.md
+++ b/content/syncbase/guides/data-model.md
@@ -5,6 +5,29 @@
toc: true
= yaml =
+{{# helpers.hidden }}
+<!-- @setupEnvironment @test -->
+```
+export PROJECT_DIR=$(mktemp -d "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX")
+cp -r $JIRI_ROOT/website/tools/android_project_stubs/example/* $PROJECT_DIR
+cat - <<EOF >> $PROJECT_DIR/app/build.gradle
+dependencies {
+ compile 'io.v:syncbase:0.1.4'
+}
+EOF
+cat - <<EOF > $PROJECT_DIR/app/src/main/java/io/v/syncbase/example/DataModel.java
+package io.v.syncbase.example;
+import io.v.syncbase.*;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+public class DataModel {
+ Database db;
+ void main() {
+EOF
+```
+{{/ helpers.hidden }}
+
# Introduction
Syncbase is a key-value storage system that handles both structured data and
blobs. The data is organized by the following hierarchy:
@@ -25,13 +48,20 @@
There is a pre-configured database for each app. `Syncbase.getDatabase()` is
used to initialize Syncbase and get a reference to the app's database.
+<!-- @createDatabase @test -->
```
-DatabaseOptions dbOpt = new DatabaseOptions();
+cat - <<EOF >> $PROJECT_DIR/app/src/main/java/io/v/syncbase/example/DataModel.java
+Syncbase.DatabaseOptions options = new Syncbase.DatabaseOptions();
+// dbOpt.cloudSyncbaseAddress = "<Your Cloud Syncbase Address>";
+// dbOpt.cloudSyncbaseBlessing = "<Your Cloud Syncbase Blessing>";
-dbOpt.cloudSyncbaseAddress = "<Your Cloud Syncbase Address>";
-dbOpt.cloudSyncbaseBlessing = "<Your Cloud Syncbase Blessing>";
-
-Database db = Syncbase.getDatabase();
+Syncbase.database(new Syncbase.DatabaseCallback() {
+ @Override
+ public void onSuccess(final Database db) {
+ // Use database to interact with Syncbase.
+ }
+}, options);
+EOF
```
Other database options include ability to set the directory where data files
@@ -66,16 +96,19 @@
restricted to alphanumeric characters plus underscore and can have a maximum
length of 64 bytes.
+<!-- @createCollection @test -->
```
-UUID collectionName = Syncbase.getUUID();
+cat - <<EOF >> $PROJECT_DIR/app/src/main/java/io/v/syncbase/example/DataModel.java
+String collectionName = UUID.randomUUID().toString();
Collection collection = db.collection(collectionName);
-UUID rowKey = Syncbase.getUUID();
+String rowKey = UUID.randomUUID().toString();
collection.put(rowKey, "myValue");
String myValue = collection.get(rowKey, String.class);
collection.delete(rowKey);
+EOF
```
As mentioned earlier, collections are synced across user's devices by default
@@ -113,22 +146,25 @@
as values and takes case of serialization. POJO classes must have an empty
constructor.
+<!-- @addPojoToCollection @test -->
```
-public class MyPojo {
- String foo;
- Integer bar;
- List<MyPojo> baz;
+cat - <<EOF >> $PROJECT_DIR/app/src/main/java/io/v/syncbase/example/DataModel.java
+class MyPojo {
+ String foo;
+ Integer bar;
+ List<MyPojo> baz;
- public MyPojo() {
- foo = null;
- bar = null;
- baz = Lists.newArrayList();
- }
+ public MyPojo() {
+ foo = null;
+ bar = null;
+ baz = new ArrayList<MyPojo>();
+ }
}
MyPojo pojoIn = new MyPojo();
-collection.put('myKey', pojo);
-MyPojo pojoOut = collection.get('myKey', MyPojo.class);
+collection.put("myKey", pojoIn);
+MyPojo pojoOut = collection.get("myKey", MyPojo.class);
+EOF
```
{{# helpers.info }}
@@ -209,4 +245,15 @@
(e.g., stock watchlist) may be shared in read-only mode with other apps.
There is no sharing between user accounts.
-[Design Doc](/syncbase/designdocs/brokerage.html)
\ No newline at end of file
+[Design Doc](/syncbase/designdocs/brokerage.html)
+
+{{# helpers.hidden }}
+<!-- @compileSnippets_mayTakeMinutes @test -->
+```
+cat - <<EOF >> $PROJECT_DIR/app/src/main/java/io/v/syncbase/example/DataModel.java
+ }
+}
+EOF
+cd $PROJECT_DIR && ./gradlew assembleRelease
+```
+{{/ helpers.hidden }}
\ No newline at end of file