mirror of https://github.com/tasks/tasks
Remove tests-sync
parent
fdb009528f
commit
9f3bc5fa84
@ -1,25 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us -->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.tasks.sync.tests"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0">
|
||||
|
||||
<uses-sdk android:minSdkVersion="7" />
|
||||
|
||||
<!-- We add an application tag here just so that we can indicate that
|
||||
this package needs to link against the android.test library,
|
||||
which is needed when building test cases. -->
|
||||
<application android:debuggable="true">
|
||||
<uses-library android:name="android.test.runner" />
|
||||
</application>
|
||||
|
||||
<!--
|
||||
This declares that this application uses the instrumentation test runner targeting
|
||||
the package of the parent app. To run the tests use the command:
|
||||
"adb shell am instrument -w com.xxx.xxx.tests/android.test.InstrumentationTestRunner"
|
||||
-->
|
||||
<instrumentation android:name="com.zutubi.android.junitreport.JUnitReportTestRunner"
|
||||
android:targetPackage="org.tasks"
|
||||
android:label="Tests for Tasks"/>
|
||||
</manifest>
|
||||
@ -1,12 +0,0 @@
|
||||
# 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,
|
||||
# "ant.properties", and override values to adapt the script to your
|
||||
# project structure.
|
||||
|
||||
# Project target.
|
||||
target=android-17
|
||||
android.library.reference.1=../api
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.0 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.7 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.5 KiB |
@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical" >
|
||||
|
||||
<TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/hello" />
|
||||
|
||||
</LinearLayout>
|
||||
@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<string name="hello">Hello World!</string>
|
||||
<string name="app_name">Astrid-tests-syncTest</string>
|
||||
|
||||
</resources>
|
||||
@ -1,327 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.gtasks;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.accounts.AccountManagerFuture;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.google.api.client.googleapis.extensions.android2.auth.GoogleAccountManager;
|
||||
import com.google.api.client.util.DateTime;
|
||||
import com.google.api.services.tasks.model.Task;
|
||||
import com.google.api.services.tasks.model.TaskList;
|
||||
import com.google.api.services.tasks.model.TaskLists;
|
||||
import com.google.api.services.tasks.model.Tasks;
|
||||
import com.todoroo.andlib.service.ContextManager;
|
||||
import com.todoroo.andlib.utility.DateUtilities;
|
||||
import com.todoroo.andlib.utility.Preferences;
|
||||
import com.todoroo.astrid.gtasks.api.GtasksApiUtilities;
|
||||
import com.todoroo.astrid.gtasks.api.GtasksInvoker;
|
||||
import com.todoroo.astrid.gtasks.api.MoveListRequest;
|
||||
import com.todoroo.astrid.gtasks.auth.GtasksTokenValidator;
|
||||
import com.todoroo.astrid.test.DatabaseTestCase;
|
||||
|
||||
@SuppressWarnings("nls")
|
||||
public class GtasksApiTest extends DatabaseTestCase {
|
||||
|
||||
private static final String DEFAULT_LIST = "@default";
|
||||
private static final String TEST_ACCOUNT = "sync_tester2@astrid.com";
|
||||
private static GtasksInvoker service;
|
||||
private static boolean initialized = false;
|
||||
private boolean bypassTests = false;
|
||||
|
||||
public void testCreateTask() throws Exception {
|
||||
if(bypassTests) return;
|
||||
Task newTask = new Task();
|
||||
String title = "New task";
|
||||
newTask.setTitle(title);
|
||||
|
||||
service.createGtask(DEFAULT_LIST, newTask);
|
||||
assertTrue(taskWithTitleExists(title));
|
||||
}
|
||||
|
||||
public void testUpdateTaskProperties() throws Exception {
|
||||
if(bypassTests) return;
|
||||
Task newTask = new Task();
|
||||
String title = "This title will change";
|
||||
newTask.setTitle(title);
|
||||
|
||||
newTask = service.createGtask(DEFAULT_LIST, newTask);
|
||||
assertTrue(taskWithTitleExists(title));
|
||||
|
||||
String title2 = "Changed Title";
|
||||
newTask.setTitle(title2);
|
||||
service.updateGtask(DEFAULT_LIST, newTask);
|
||||
assertTrue(taskWithTitleExists(title2));
|
||||
assertFalse(taskWithTitleExists(title));
|
||||
}
|
||||
|
||||
public void testTaskDateFormatting2() throws Exception {
|
||||
if(bypassTests) return;
|
||||
Task newTask = new Task();
|
||||
String title = "Due date will change";
|
||||
newTask.setTitle(title);
|
||||
|
||||
newTask = service.createGtask(DEFAULT_LIST, newTask);
|
||||
assertTrue(taskWithTitleExists(title));
|
||||
newTask = service.getGtask(DEFAULT_LIST, newTask.getId());
|
||||
System.err.println("Newtask A: " + newTask.getDue());
|
||||
|
||||
long now = DateUtilities.now();
|
||||
newTask.setDue(GtasksApiUtilities.unixTimeToGtasksDueDate(now));
|
||||
System.err.println("Newtask B: " + newTask.getDue());
|
||||
newTask = service.updateGtask(DEFAULT_LIST, newTask);
|
||||
System.err.println("Newtask C: " + newTask.getDue());
|
||||
|
||||
long complete = now + DateUtilities.ONE_DAY;
|
||||
newTask.setCompleted(GtasksApiUtilities.unixTimeToGtasksCompletionTime(complete));
|
||||
System.err.println("Newtask D: " + newTask.getCompleted());
|
||||
newTask.setStatus("completed");
|
||||
newTask = service.updateGtask(DEFAULT_LIST, newTask);
|
||||
System.err.println("Newtask E: " + newTask.getCompleted());
|
||||
}
|
||||
|
||||
public void testTaskDateFormatting() throws Exception {
|
||||
if(bypassTests) return;
|
||||
Task newTask = new Task();
|
||||
String title = "Due date will change";
|
||||
newTask.setTitle(title);
|
||||
|
||||
newTask = service.createGtask(DEFAULT_LIST, newTask);
|
||||
assertTrue(taskWithTitleExists(title));
|
||||
|
||||
long dueTime = new Date(114, 1, 13).getTime();
|
||||
DateTime dueTimeString = GtasksApiUtilities.unixTimeToGtasksDueDate(dueTime);
|
||||
newTask.setDue(dueTimeString);
|
||||
newTask = service.updateGtask(DEFAULT_LIST, newTask);
|
||||
//assertEquals(dueTimeString, GtasksApiUtilities.gtasksDueTimeStringToLocalTimeString(newTask.due));
|
||||
assertEquals(dueTime, GtasksApiUtilities.gtasksDueTimeToUnixTime(newTask.getDue(), 0));
|
||||
|
||||
long compTime = new Date(115, 2, 14).getTime();
|
||||
DateTime compTimeString = GtasksApiUtilities.unixTimeToGtasksCompletionTime(compTime);
|
||||
newTask.setCompleted(compTimeString);
|
||||
newTask.setStatus("completed");
|
||||
newTask = service.updateGtask(DEFAULT_LIST, newTask);
|
||||
//assertEquals(compTimeString, GtasksApiUtilities.gtasksCompletedTimeStringToLocalTimeString(newTask.completed));
|
||||
assertEquals(compTime, GtasksApiUtilities.gtasksCompletedTimeToUnixTime(newTask.getCompleted(), 0));
|
||||
}
|
||||
|
||||
public void testTaskDeleted() throws Exception {
|
||||
if(bypassTests) return;
|
||||
Task newTask = new Task();
|
||||
String title = "This task will be deleted";
|
||||
newTask.setTitle(title);
|
||||
|
||||
newTask = service.createGtask(DEFAULT_LIST, newTask);
|
||||
assertTrue(taskWithTitleExists(title));
|
||||
|
||||
service.deleteGtask(DEFAULT_LIST, newTask.getId());
|
||||
assertFalse(taskWithTitleExists(title));
|
||||
}
|
||||
|
||||
public void testTaskMoved() throws Exception {
|
||||
if(bypassTests) return;
|
||||
Task newTask1 = new Task();
|
||||
String title1 = "Task 1";
|
||||
newTask1.setTitle(title1);
|
||||
|
||||
Task newTask2 = new Task();
|
||||
String title2 = "Task 2";
|
||||
newTask2.setTitle(title2);
|
||||
|
||||
newTask1 = service.createGtask(DEFAULT_LIST, newTask1);
|
||||
newTask2 = service.createGtask(DEFAULT_LIST, newTask2);
|
||||
|
||||
assertTrue(taskWithTitleExists(title1));
|
||||
assertTrue(taskWithTitleExists(title2));
|
||||
|
||||
System.err.println("Task 1 id: " + newTask1.getId());
|
||||
System.err.println("Task 2 id: " + newTask2.getId());
|
||||
|
||||
service.moveGtask(DEFAULT_LIST, newTask1.getId(), newTask2.getId(), null);
|
||||
newTask1 = service.getGtask(DEFAULT_LIST, newTask1.getId());
|
||||
newTask2 = service.getGtask(DEFAULT_LIST, newTask2.getId());
|
||||
|
||||
assertEquals(newTask1.getParent(), newTask2.getId());
|
||||
|
||||
service.moveGtask(DEFAULT_LIST, newTask1.getId(), null, newTask2.getId());
|
||||
newTask1 = service.getGtask(DEFAULT_LIST, newTask1.getId());
|
||||
newTask2 = service.getGtask(DEFAULT_LIST, newTask2.getId());
|
||||
|
||||
assertNull(newTask1.getParent());
|
||||
assertTrue(newTask2.getPosition().compareTo(newTask1.getPosition()) < 0);
|
||||
}
|
||||
|
||||
public void testMoveBetweenLists() throws Exception {
|
||||
if(bypassTests) return;
|
||||
Task newTask = new Task();
|
||||
String title = "This task will move lists";
|
||||
newTask.setTitle(title);
|
||||
|
||||
newTask = service.createGtask(DEFAULT_LIST, newTask);
|
||||
assertTrue(taskWithTitleExists(title));
|
||||
|
||||
String listTitle = "New list";
|
||||
service.createGtaskList(listTitle);
|
||||
TaskList newList;
|
||||
|
||||
assertNotNull(newList = listWithTitle(listTitle));
|
||||
|
||||
MoveListRequest moveTask = new MoveListRequest(service, newTask.getId(), DEFAULT_LIST, newList.getId(), null);
|
||||
moveTask.executePush();
|
||||
|
||||
assertFalse(taskWithTitleExists(title));
|
||||
assertTrue(listHasTaskWithTitle(newList.getId(), title));
|
||||
}
|
||||
|
||||
private boolean listHasTaskWithTitle(String listId, String title) throws Exception {
|
||||
com.google.api.services.tasks.model.Tasks newListTasks = service.getAllGtasksFromListId(listId, false, false, 0);
|
||||
List<Task> items = newListTasks.getItems();
|
||||
if (items != null) {
|
||||
for (Task t : items) {
|
||||
if (t.getTitle().equals(title)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean taskWithTitleExists(String title) throws Exception {
|
||||
Tasks defaultList = service.getAllGtasksFromListId(DEFAULT_LIST, false, false, 0);
|
||||
List<Task> items = defaultList.getItems();
|
||||
if (items != null) {
|
||||
for (Task t : items) {
|
||||
if (t.getTitle().equals(title))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void testCreateList() throws Exception {
|
||||
if(bypassTests) return;
|
||||
String title1 = "My new list!";
|
||||
service.createGtaskList(title1);
|
||||
assertNotNull(listWithTitle(title1));
|
||||
|
||||
String title2 = "Another new list!";
|
||||
service.createGtaskList("Another new list!");
|
||||
assertNotNull(listWithTitle(title2));
|
||||
assertNotNull(listWithTitle(title1));
|
||||
}
|
||||
|
||||
public void testDeleteList() throws Exception {
|
||||
if(bypassTests) return;
|
||||
String title = "This list will be deleted";
|
||||
TaskList t = service.createGtaskList(title);
|
||||
assertNotNull(listWithTitle(title));
|
||||
|
||||
service.deleteGtaskList(t.getId());
|
||||
assertNull(listWithTitle(title));
|
||||
}
|
||||
|
||||
public void testUpdateListProperties() throws Exception {
|
||||
if(bypassTests) return;
|
||||
String title1 = "This title will change";
|
||||
TaskList t = service.createGtaskList(title1);
|
||||
assertNotNull(listWithTitle(title1));
|
||||
|
||||
String title2 = "New title";
|
||||
t.setTitle(title2);
|
||||
service.updateGtaskList(t);
|
||||
assertNotNull(listWithTitle(title2));
|
||||
assertNull(listWithTitle(title1));
|
||||
}
|
||||
|
||||
private TaskList listWithTitle(String title) throws Exception {
|
||||
TaskLists allLists = service.allGtaskLists();
|
||||
List<TaskList> items = allLists.getItems();
|
||||
for (TaskList t : items) {
|
||||
if (t.getTitle().equals(title))
|
||||
return t;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
if (!initialized) {
|
||||
GoogleAccountManager manager = new GoogleAccountManager(ContextManager.getContext());
|
||||
Account[] accounts = manager.getAccounts();
|
||||
Account toUse = null;
|
||||
for (Account a : accounts) {
|
||||
if (a.name.equals(TEST_ACCOUNT)) {
|
||||
toUse = a;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (toUse == null) {
|
||||
if (accounts.length == 0) {
|
||||
bypassTests = true;
|
||||
return;
|
||||
}
|
||||
toUse = accounts[0];
|
||||
}
|
||||
|
||||
Preferences.setString(GtasksPreferenceService.PREF_USER_NAME, toUse.name);
|
||||
AccountManagerFuture<Bundle> accountManagerFuture = manager.manager.getAuthToken(toUse, GtasksInvoker.AUTH_TOKEN_TYPE, true, null, null);
|
||||
|
||||
Bundle authTokenBundle = accountManagerFuture.getResult();
|
||||
if (authTokenBundle.containsKey(AccountManager.KEY_INTENT)) {
|
||||
Intent i = (Intent) authTokenBundle.get(AccountManager.KEY_INTENT);
|
||||
ContextManager.getContext().startActivity(i);
|
||||
return;
|
||||
}
|
||||
|
||||
String authToken = authTokenBundle.getString(AccountManager.KEY_AUTHTOKEN);
|
||||
authToken = GtasksTokenValidator.validateAuthToken(getContext(), authToken);
|
||||
|
||||
service = new GtasksInvoker(authToken);
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
deleteAllLists();
|
||||
clearDefaultList();
|
||||
}
|
||||
|
||||
private void deleteAllLists() {
|
||||
try {
|
||||
TaskLists allLists = service.allGtaskLists();
|
||||
List<TaskList> items = allLists.getItems();
|
||||
for (TaskList t : items) {
|
||||
if (!t.getTitle().equals("Default List"))
|
||||
service.deleteGtaskList(t.getId());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
fail("Failed to clear lists");
|
||||
}
|
||||
}
|
||||
|
||||
private void clearDefaultList() {
|
||||
try {
|
||||
Tasks tasks = service.getAllGtasksFromListId(DEFAULT_LIST, false, false, 0);
|
||||
List<Task> items = tasks.getItems();
|
||||
if (items != null) {
|
||||
for (Task t : items) {
|
||||
service.deleteGtask(DEFAULT_LIST, t.getId());
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
fail("Failed to clear default list");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,571 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.gtasks;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Semaphore;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.accounts.AccountManagerFuture;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.google.api.client.googleapis.extensions.android2.auth.GoogleAccountManager;
|
||||
import com.google.api.services.tasks.model.Tasks;
|
||||
import com.todoroo.andlib.data.TodorooCursor;
|
||||
import com.todoroo.andlib.service.Autowired;
|
||||
import com.todoroo.andlib.service.ContextManager;
|
||||
import com.todoroo.andlib.sql.Criterion;
|
||||
import com.todoroo.andlib.sql.Query;
|
||||
import com.todoroo.andlib.utility.AndroidUtilities;
|
||||
import com.todoroo.andlib.utility.DateUtilities;
|
||||
import com.todoroo.andlib.utility.Preferences;
|
||||
import com.todoroo.astrid.data.Metadata;
|
||||
import com.todoroo.astrid.data.Task;
|
||||
import com.todoroo.astrid.gtasks.api.GtasksApiUtilities;
|
||||
import com.todoroo.astrid.gtasks.api.GtasksInvoker;
|
||||
import com.todoroo.astrid.gtasks.auth.GtasksTokenValidator;
|
||||
import com.todoroo.astrid.gtasks.sync.GtasksSyncV2Provider;
|
||||
import com.todoroo.astrid.service.MetadataService;
|
||||
import com.todoroo.astrid.service.TaskService;
|
||||
import com.todoroo.astrid.sync.SyncResultCallbackAdapter;
|
||||
import com.todoroo.astrid.test.DatabaseTestCase;
|
||||
|
||||
@SuppressWarnings("nls")
|
||||
public class GtasksNewSyncTest extends DatabaseTestCase {
|
||||
|
||||
private static GtasksInvoker gtasksService;
|
||||
private static boolean initialized = false;
|
||||
private boolean bypassTests = false;
|
||||
|
||||
private static String DEFAULT_LIST = "@default";
|
||||
private static final String TEST_ACCOUNT = "sync_tester2@astrid.com";
|
||||
private static final long TIME_BETWEEN_SYNCS = 3000l;
|
||||
|
||||
@Autowired TaskService taskService;
|
||||
@Autowired MetadataService metadataService;
|
||||
@Autowired GtasksMetadataService gtasksMetadataService;
|
||||
@Autowired GtasksPreferenceService gtasksPreferenceService;
|
||||
|
||||
/*
|
||||
* Basic creation tests
|
||||
*/
|
||||
public void testTaskCreatedLocally() {
|
||||
if(bypassTests) return;
|
||||
String title = "Astrid task 1";
|
||||
Task localTask = createNewLocalTask(title);
|
||||
|
||||
whenInvokeSync();
|
||||
|
||||
assertTaskExistsRemotely(localTask, title);
|
||||
}
|
||||
|
||||
public void testTaskCreatedRemotely() throws Exception {
|
||||
if(bypassTests) return;
|
||||
String title = "Gtasks task 1";
|
||||
com.google.api.services.tasks.model.Task remoteTask = new com.google.api.services.tasks.model.Task();
|
||||
remoteTask.setTitle(title);
|
||||
remoteTask = gtasksService.createGtask(DEFAULT_LIST, remoteTask);
|
||||
|
||||
whenInvokeSync();
|
||||
|
||||
assertTaskExistsLocally(remoteTask, title);
|
||||
}
|
||||
|
||||
/*
|
||||
* Title editing tests
|
||||
*/
|
||||
public void testTitleChangedLocally() throws Exception {
|
||||
if(bypassTests) return;
|
||||
String title = "Astrid task 2";
|
||||
Task localTask = createNewLocalTask(title);
|
||||
|
||||
whenInvokeSync();
|
||||
|
||||
com.google.api.services.tasks.model.Task remoteTask = assertTaskExistsRemotely(localTask, title);
|
||||
AndroidUtilities.sleepDeep(TIME_BETWEEN_SYNCS);
|
||||
|
||||
//Set new title on local task
|
||||
String newTitle = "Astrid task 2 edited";
|
||||
localTask.setTITLE(newTitle);
|
||||
taskService.save(localTask);
|
||||
|
||||
whenInvokeSync();
|
||||
|
||||
//Refetch remote task and assert that both local and remote titles match expected
|
||||
localTask = refetchLocalTask(localTask);
|
||||
remoteTask = refetchRemoteTask(remoteTask);
|
||||
assertEquals(newTitle, localTask.getTITLE());
|
||||
assertEquals(newTitle, remoteTask.getTitle());
|
||||
}
|
||||
|
||||
public void testTitleChangedRemotely() throws Exception {
|
||||
if(bypassTests) return;
|
||||
String title = "Astrid task 3";
|
||||
Task localTask = createNewLocalTask(title);
|
||||
|
||||
whenInvokeSync();
|
||||
|
||||
com.google.api.services.tasks.model.Task remoteTask = assertTaskExistsRemotely(localTask, title);
|
||||
AndroidUtilities.sleepDeep(TIME_BETWEEN_SYNCS);
|
||||
|
||||
//Set new title on remote task
|
||||
String newRemoteTitle = "Task 3 edited on gtasks";
|
||||
remoteTask.setTitle(newRemoteTitle);
|
||||
gtasksService.updateGtask(DEFAULT_LIST, remoteTask);
|
||||
|
||||
whenInvokeSync();
|
||||
|
||||
//Refetch local/remote tasks, assert that both titles match expected
|
||||
remoteTask = refetchRemoteTask(remoteTask);
|
||||
localTask = refetchLocalTask(localTask);
|
||||
assertEquals(newRemoteTitle, remoteTask.getTitle());
|
||||
assertEquals(newRemoteTitle, localTask.getTITLE());
|
||||
}
|
||||
|
||||
public void testDateChangedLocally() throws Exception {
|
||||
if(bypassTests) return;
|
||||
Task localTask = createLocalTaskForDateTests(" locally");
|
||||
String title = localTask.getTITLE();
|
||||
long startDate = localTask.getDUE_DATE();
|
||||
|
||||
whenInvokeSync();
|
||||
com.google.api.services.tasks.model.Task remoteTask = assertTaskExistsRemotely(localTask, title);
|
||||
localTask = refetchLocalTask(localTask);
|
||||
assertTrue(String.format("Expected %s, was %s", new Date(startDate), new Date(localTask.getDUE_DATE())),
|
||||
Math.abs(startDate - localTask.getDUE_DATE()) < 5000);
|
||||
long dueDate = GtasksApiUtilities.gtasksDueTimeToUnixTime(remoteTask.getDue(), 0);
|
||||
long createdDate = Task.createDueDate(Task.URGENCY_SPECIFIC_DAY, dueDate);
|
||||
assertEquals(startDate, createdDate);
|
||||
AndroidUtilities.sleepDeep(TIME_BETWEEN_SYNCS);
|
||||
|
||||
//Set new due date on local task
|
||||
long newDueDate = Task.createDueDate(Task.URGENCY_SPECIFIC_DAY, new Date(116, 1, 8).getTime());
|
||||
localTask.setDUE_DATE(newDueDate);
|
||||
taskService.save(localTask);
|
||||
|
||||
whenInvokeSync();
|
||||
|
||||
//Refetch remote task and assert that both tasks match expected due date
|
||||
localTask = refetchLocalTask(localTask);
|
||||
remoteTask = refetchRemoteTask(remoteTask);
|
||||
assertEquals(newDueDate, localTask.getDUE_DATE().longValue());
|
||||
dueDate = GtasksApiUtilities.gtasksDueTimeToUnixTime(remoteTask.getDue(), 0);
|
||||
createdDate = Task.createDueDate(Task.URGENCY_SPECIFIC_DAY, dueDate);
|
||||
assertEquals(newDueDate, createdDate);
|
||||
}
|
||||
|
||||
public void testDateChangedRemotely() throws Exception {
|
||||
if(bypassTests) return;
|
||||
Task localTask = createLocalTaskForDateTests(" remotely");
|
||||
String title = localTask.getTITLE();
|
||||
long startDate = localTask.getDUE_DATE();
|
||||
|
||||
whenInvokeSync();
|
||||
com.google.api.services.tasks.model.Task remoteTask = assertTaskExistsRemotely(localTask, title);
|
||||
localTask = refetchLocalTask(localTask);
|
||||
assertTrue(String.format("Expected %s, was %s", new Date(startDate), new Date(localTask.getDUE_DATE())),
|
||||
Math.abs(startDate - localTask.getDUE_DATE()) < 5000);
|
||||
long dueDate = GtasksApiUtilities.gtasksDueTimeToUnixTime(remoteTask.getDue(), 0);
|
||||
long createdDate = Task.createDueDate(Task.URGENCY_SPECIFIC_DAY, dueDate);
|
||||
assertEquals(startDate, createdDate);
|
||||
AndroidUtilities.sleepDeep(TIME_BETWEEN_SYNCS);
|
||||
|
||||
//Set new due date on remote task
|
||||
long newDueDate = new Date(116, 1, 8).getTime();
|
||||
remoteTask.setDue(GtasksApiUtilities.unixTimeToGtasksDueDate(newDueDate));
|
||||
newDueDate = Task.createDueDate(Task.URGENCY_SPECIFIC_DAY, newDueDate);
|
||||
gtasksService.updateGtask(DEFAULT_LIST, remoteTask);
|
||||
|
||||
whenInvokeSync();
|
||||
|
||||
//Refetch remote task and assert that both tasks match expected due date
|
||||
localTask = refetchLocalTask(localTask);
|
||||
remoteTask = refetchRemoteTask(remoteTask);
|
||||
assertEquals(newDueDate, localTask.getDUE_DATE().longValue());
|
||||
dueDate = GtasksApiUtilities.gtasksDueTimeToUnixTime(remoteTask.getDue(), 0);
|
||||
createdDate = Task.createDueDate(Task.URGENCY_SPECIFIC_DAY, dueDate);
|
||||
assertEquals(newDueDate, createdDate);
|
||||
|
||||
}
|
||||
|
||||
public void testDateChangedBoth_ChooseLocal() throws Exception {
|
||||
if(bypassTests) return;
|
||||
Task localTask = createLocalTaskForDateTests(" remotely");
|
||||
String title = localTask.getTITLE();
|
||||
long startDate = localTask.getDUE_DATE();
|
||||
|
||||
whenInvokeSync();
|
||||
com.google.api.services.tasks.model.Task remoteTask = assertTaskExistsRemotely(localTask, title);
|
||||
localTask = refetchLocalTask(localTask);
|
||||
assertTrue(String.format("Expected %s, was %s", new Date(startDate), new Date(localTask.getDUE_DATE())),
|
||||
Math.abs(startDate - localTask.getDUE_DATE()) < 5000);
|
||||
long dueDate = GtasksApiUtilities.gtasksDueTimeToUnixTime(remoteTask.getDue(), 0);
|
||||
long createdDate = Task.createDueDate(Task.URGENCY_SPECIFIC_DAY, dueDate);
|
||||
assertEquals(startDate, createdDate);
|
||||
AndroidUtilities.sleepDeep(TIME_BETWEEN_SYNCS);
|
||||
|
||||
//Set new due date on remote task first
|
||||
long newLocalDate = Task.createDueDate(Task.URGENCY_SPECIFIC_DAY, new Date(128, 5, 11).getTime());
|
||||
long newRemoteDate = new Date(121, 5, 25).getTime();
|
||||
|
||||
remoteTask.setDue(GtasksApiUtilities.unixTimeToGtasksDueDate(newRemoteDate));
|
||||
gtasksService.updateGtask(DEFAULT_LIST, remoteTask);
|
||||
|
||||
AndroidUtilities.sleepDeep(TIME_BETWEEN_SYNCS);
|
||||
|
||||
localTask.setDUE_DATE(newLocalDate);
|
||||
taskService.save(localTask);
|
||||
|
||||
whenInvokeSync();
|
||||
|
||||
//Refetch both and assert that due dates match the one we set to local (more recent)
|
||||
localTask = refetchLocalTask(localTask);
|
||||
remoteTask = refetchRemoteTask(remoteTask);
|
||||
assertEquals(newLocalDate, localTask.getDUE_DATE().longValue());
|
||||
dueDate = GtasksApiUtilities.gtasksDueTimeToUnixTime(remoteTask.getDue(), 0);
|
||||
createdDate = Task.createDueDate(Task.URGENCY_SPECIFIC_DAY, dueDate);
|
||||
assertEquals(newLocalDate, createdDate);
|
||||
}
|
||||
|
||||
public void DISABLED_testDateChangedBoth_ChooseRemote() throws Exception {
|
||||
if(bypassTests) return;
|
||||
Task localTask = createLocalTaskForDateTests(" remotely");
|
||||
String title = localTask.getTITLE();
|
||||
long startDate = localTask.getDUE_DATE();
|
||||
|
||||
whenInvokeSync();
|
||||
com.google.api.services.tasks.model.Task remoteTask = assertTaskExistsRemotely(localTask, title);
|
||||
localTask = refetchLocalTask(localTask);
|
||||
assertTrue(String.format("Expected %s, was %s", new Date(startDate), new Date(localTask.getDUE_DATE())),
|
||||
Math.abs(startDate - localTask.getDUE_DATE()) < 5000);
|
||||
assertEquals(startDate, GtasksApiUtilities.gtasksDueTimeToUnixTime(remoteTask.getDue(), 0));
|
||||
AndroidUtilities.sleepDeep(TIME_BETWEEN_SYNCS);
|
||||
|
||||
|
||||
//Set new due date on local task first
|
||||
long newLocalDate = new Date(128, 5, 11).getTime();
|
||||
long newRemoteDate = new Date(121, 5, 25).getTime();
|
||||
|
||||
localTask.setDUE_DATE(newLocalDate);
|
||||
taskService.save(localTask);
|
||||
|
||||
AndroidUtilities.sleepDeep(TIME_BETWEEN_SYNCS);
|
||||
|
||||
remoteTask.setDue(GtasksApiUtilities.unixTimeToGtasksDueDate(newRemoteDate));
|
||||
gtasksService.updateGtask(DEFAULT_LIST, remoteTask);
|
||||
|
||||
whenInvokeSync();
|
||||
|
||||
//Refetch both and assert that due dates match the one we set to local (more recent)
|
||||
localTask = refetchLocalTask(localTask);
|
||||
remoteTask = refetchRemoteTask(remoteTask);
|
||||
assertEquals(newLocalDate, localTask.getDUE_DATE().longValue());
|
||||
assertEquals(newLocalDate, GtasksApiUtilities.gtasksDueTimeToUnixTime(remoteTask.getDue(), 0));
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper method for due date tests
|
||||
*/
|
||||
private Task createLocalTaskForDateTests(String addToTitle) {
|
||||
Task localTask = createNewLocalTask("Due date will change" + addToTitle);
|
||||
Date date = new Date(115, 2, 14);
|
||||
date.setHours(12);
|
||||
date.setMinutes(0);
|
||||
date.setSeconds(0);
|
||||
long dueDate = date.getTime();
|
||||
localTask.setDUE_DATE(dueDate);
|
||||
taskService.save(localTask);
|
||||
|
||||
return localTask;
|
||||
}
|
||||
|
||||
public void testNoteEditedLocally() throws Exception {
|
||||
if(bypassTests) return;
|
||||
Task localTask = createLocalTaskForNoteTests(" locally");
|
||||
String title = localTask.getTITLE();
|
||||
String originalNote = localTask.getNOTES();
|
||||
|
||||
whenInvokeSync();
|
||||
|
||||
com.google.api.services.tasks.model.Task remoteTask = assertTaskExistsRemotely(localTask, title);
|
||||
assertEquals(originalNote, localTask.getNOTES());
|
||||
assertEquals(originalNote, remoteTask.getNotes());
|
||||
|
||||
AndroidUtilities.sleepDeep(TIME_BETWEEN_SYNCS);
|
||||
|
||||
String newNote = "New local note";
|
||||
localTask.setNOTES(newNote);
|
||||
taskService.save(localTask);
|
||||
|
||||
whenInvokeSync();
|
||||
|
||||
localTask = refetchLocalTask(localTask);
|
||||
remoteTask = refetchRemoteTask(remoteTask);
|
||||
assertEquals(newNote, localTask.getNOTES());
|
||||
assertEquals(newNote, remoteTask.getNotes());
|
||||
}
|
||||
|
||||
public void testNoteEditedRemotely() throws Exception {
|
||||
if(bypassTests) return;
|
||||
Task localTask = createLocalTaskForNoteTests(" remotely");
|
||||
String title = localTask.getTITLE();
|
||||
String originalNote = localTask.getNOTES();
|
||||
|
||||
whenInvokeSync();
|
||||
|
||||
com.google.api.services.tasks.model.Task remoteTask = assertTaskExistsRemotely(localTask, title);
|
||||
assertEquals(originalNote, localTask.getNOTES());
|
||||
assertEquals(originalNote, remoteTask.getNotes());
|
||||
|
||||
AndroidUtilities.sleepDeep(TIME_BETWEEN_SYNCS);
|
||||
|
||||
String newNote = "New remote note";
|
||||
remoteTask.setNotes(newNote);
|
||||
gtasksService.updateGtask(DEFAULT_LIST, remoteTask);
|
||||
|
||||
whenInvokeSync();
|
||||
|
||||
localTask = refetchLocalTask(localTask);
|
||||
remoteTask = refetchRemoteTask(remoteTask);
|
||||
assertEquals(newNote, localTask.getNOTES());
|
||||
assertEquals(newNote, remoteTask.getNotes());
|
||||
}
|
||||
|
||||
public void DISABLED_testNoteEditedBoth() throws Exception {
|
||||
if(bypassTests) return;
|
||||
Task localTask = createLocalTaskForNoteTests(" remotely");
|
||||
String title = localTask.getTITLE();
|
||||
String originalNote = localTask.getNOTES();
|
||||
|
||||
whenInvokeSync();
|
||||
|
||||
com.google.api.services.tasks.model.Task remoteTask = assertTaskExistsRemotely(localTask, title);
|
||||
assertEquals(originalNote, localTask.getNOTES());
|
||||
assertEquals(originalNote, remoteTask.getNotes());
|
||||
|
||||
AndroidUtilities.sleepDeep(TIME_BETWEEN_SYNCS);
|
||||
|
||||
String newLocalNote = "New local note";
|
||||
String newRemoteNote = "New remote note";
|
||||
|
||||
localTask.setNOTES(newLocalNote);
|
||||
taskService.save(localTask);
|
||||
|
||||
AndroidUtilities.sleepDeep(TIME_BETWEEN_SYNCS);
|
||||
|
||||
remoteTask.setNotes(newRemoteNote);
|
||||
gtasksService.updateGtask(DEFAULT_LIST, remoteTask);
|
||||
|
||||
whenInvokeSync();
|
||||
|
||||
localTask = refetchLocalTask(localTask);
|
||||
remoteTask = refetchRemoteTask(remoteTask);
|
||||
System.err.println("Local note: " + localTask.getNOTES());
|
||||
System.err.println("Remote note: " + remoteTask.getNotes());
|
||||
}
|
||||
|
||||
private Task createLocalTaskForNoteTests(String addToTitle) {
|
||||
Task localTask = createNewLocalTask("Note will change" + addToTitle);
|
||||
String note = "Original note";
|
||||
localTask.setNOTES(note);
|
||||
taskService.save(localTask);
|
||||
|
||||
return localTask;
|
||||
}
|
||||
|
||||
/*
|
||||
* Completion tests
|
||||
*/
|
||||
|
||||
public void testTaskCompletedLocally() throws Exception {
|
||||
if(bypassTests) return;
|
||||
String title = "Will complete locally";
|
||||
Task localTask = createNewLocalTask(title);
|
||||
|
||||
whenInvokeSync();
|
||||
com.google.api.services.tasks.model.Task remoteTask = assertTaskExistsRemotely(localTask, title);
|
||||
|
||||
AndroidUtilities.sleepDeep(TIME_BETWEEN_SYNCS);
|
||||
|
||||
long completion = DateUtilities.now();
|
||||
localTask.setCompletionDate(completion);
|
||||
taskService.save(localTask);
|
||||
|
||||
whenInvokeSync();
|
||||
|
||||
localTask = refetchLocalTask(localTask);
|
||||
remoteTask = refetchRemoteTask(remoteTask);
|
||||
assertTrue(String.format("Expected %s, was %s", new Date(completion), new Date(localTask.getCOMPLETION_DATE())),
|
||||
Math.abs(completion - localTask.getCOMPLETION_DATE()) < 5000);
|
||||
assertEquals("completed", remoteTask.getStatus());
|
||||
}
|
||||
|
||||
public void testTaskCompletedRemotely() throws Exception {
|
||||
if(bypassTests) return;
|
||||
String title = "Will complete remotely";
|
||||
Task localTask = createNewLocalTask(title);
|
||||
|
||||
whenInvokeSync();
|
||||
com.google.api.services.tasks.model.Task remoteTask = assertTaskExistsRemotely(localTask, title);
|
||||
|
||||
AndroidUtilities.sleepDeep(TIME_BETWEEN_SYNCS);
|
||||
|
||||
long completion = DateUtilities.now();
|
||||
remoteTask.setStatus("completed");
|
||||
remoteTask.setCompleted(GtasksApiUtilities.unixTimeToGtasksCompletionTime(completion));
|
||||
gtasksService.updateGtask(DEFAULT_LIST, remoteTask);
|
||||
|
||||
whenInvokeSync();
|
||||
|
||||
localTask = refetchLocalTask(localTask);
|
||||
remoteTask = refetchRemoteTask(remoteTask);
|
||||
assertTrue(String.format("Expected %s, was %s", new Date(completion), new Date(localTask.getCOMPLETION_DATE())),
|
||||
Math.abs(completion - localTask.getCOMPLETION_DATE()) < 5000);
|
||||
assertEquals("completed", remoteTask.getStatus());
|
||||
}
|
||||
|
||||
private com.google.api.services.tasks.model.Task assertTaskExistsRemotely(Task localTask, String title) {
|
||||
//Get the corresponding remote id for a local task
|
||||
Metadata metadata = gtasksMetadataService.getTaskMetadata(localTask.getId());
|
||||
String taskId = metadata.getValue(GtasksMetadata.ID);
|
||||
String listId = metadata.getValue(GtasksMetadata.LIST_ID);
|
||||
|
||||
//Fetch the remote task belonging to that id
|
||||
com.google.api.services.tasks.model.Task remoteTask = null;
|
||||
try {
|
||||
remoteTask = gtasksService.getGtask(listId, taskId);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
fail("Failed to find remote task " + taskId);
|
||||
}
|
||||
|
||||
//Do a basic title match
|
||||
assertNotNull(remoteTask);
|
||||
assertEquals(title, localTask.getTITLE());
|
||||
assertEquals(title, remoteTask.getTitle());
|
||||
return remoteTask;
|
||||
}
|
||||
|
||||
private Task assertTaskExistsLocally(com.google.api.services.tasks.model.Task remoteTask, String title) {
|
||||
long localId = localIdForTask(remoteTask);
|
||||
|
||||
//Fetch the local task from the database
|
||||
Task localTask = taskService.fetchById(localId, Task.PROPERTIES);
|
||||
|
||||
assertNotNull(localTask);
|
||||
assertEquals(title, remoteTask.getTitle());
|
||||
assertEquals(title, localTask.getTITLE());
|
||||
return localTask;
|
||||
}
|
||||
|
||||
private Task refetchLocalTask(Task localTask) {
|
||||
return taskService.fetchById(localTask.getID(), Task.PROPERTIES);
|
||||
}
|
||||
|
||||
private com.google.api.services.tasks.model.Task refetchRemoteTask(com.google.api.services.tasks.model.Task remoteTask) throws Exception {
|
||||
return gtasksService.getGtask(DEFAULT_LIST, remoteTask.getId());
|
||||
}
|
||||
|
||||
private long localIdForTask(com.google.api.services.tasks.model.Task remoteTask) {
|
||||
TodorooCursor<Metadata> cursor = metadataService.query(Query.select(Metadata.TASK).
|
||||
where(Criterion.and(Metadata.KEY.eq(GtasksMetadata.METADATA_KEY), GtasksMetadata.ID.eq(remoteTask.getId()))));
|
||||
try {
|
||||
assertEquals(1, cursor.getCount());
|
||||
|
||||
cursor.moveToFirst();
|
||||
return cursor.get(Metadata.TASK);
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Create a new Astrid task and save it to the database
|
||||
private Task createNewLocalTask(String title) {
|
||||
Task task = new Task();
|
||||
task.setTITLE(title);
|
||||
taskService.save(task);
|
||||
return task;
|
||||
}
|
||||
|
||||
//Perform a synchronization
|
||||
private void whenInvokeSync() {
|
||||
final Semaphore sema = new Semaphore(0);
|
||||
GtasksSyncV2Provider.getInstance().synchronizeActiveTasks(true, new SyncResultCallbackAdapter() {
|
||||
@Override
|
||||
public void finished() {
|
||||
sema.release();
|
||||
}
|
||||
});
|
||||
try {
|
||||
sema.acquire();
|
||||
} catch (InterruptedException e) {
|
||||
fail("Interrupted while waiting for sync to finish");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
if (!initialized) {
|
||||
initializeTestService();
|
||||
}
|
||||
|
||||
setupTestList();
|
||||
}
|
||||
|
||||
private void initializeTestService() throws Exception {
|
||||
GoogleAccountManager manager = new GoogleAccountManager(ContextManager.getContext());
|
||||
Account[] accounts = manager.getAccounts();
|
||||
|
||||
Account toUse = null;
|
||||
for (Account a : accounts) {
|
||||
if (a.name.equals(TEST_ACCOUNT)) {
|
||||
toUse = a;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (toUse == null) {
|
||||
if (accounts.length == 0) {
|
||||
bypassTests = true;
|
||||
return;
|
||||
}
|
||||
toUse = accounts[0];
|
||||
}
|
||||
|
||||
Preferences.setString(GtasksPreferenceService.PREF_USER_NAME, toUse.name);
|
||||
AccountManagerFuture<Bundle> accountManagerFuture = manager.manager.getAuthToken(toUse, "oauth2:https://www.googleapis.com/auth/tasks", true, null, null);
|
||||
|
||||
Bundle authTokenBundle = accountManagerFuture.getResult();
|
||||
if (authTokenBundle.containsKey(AccountManager.KEY_INTENT)) {
|
||||
Intent i = (Intent) authTokenBundle.get(AccountManager.KEY_INTENT);
|
||||
ContextManager.getContext().startActivity(i);
|
||||
return;
|
||||
}
|
||||
String authToken = authTokenBundle.getString(AccountManager.KEY_AUTHTOKEN);
|
||||
authToken = GtasksTokenValidator.validateAuthToken(getContext(), authToken);
|
||||
gtasksPreferenceService.setToken(authToken);
|
||||
|
||||
gtasksService = new GtasksInvoker(authToken);
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
private void setupTestList() throws Exception {
|
||||
Tasks defaultListTasks = gtasksService.getAllGtasksFromListId(DEFAULT_LIST, false, false, 0);
|
||||
List<com.google.api.services.tasks.model.Task> items = defaultListTasks.getItems();
|
||||
if (items != null) {
|
||||
for (com.google.api.services.tasks.model.Task t : items) {
|
||||
gtasksService.deleteGtask(DEFAULT_LIST, t.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,225 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.gtasks;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.accounts.AccountManagerFuture;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.google.api.client.googleapis.extensions.android2.auth.GoogleAccountManager;
|
||||
import com.google.api.services.tasks.model.Tasks;
|
||||
import com.todoroo.andlib.service.Autowired;
|
||||
import com.todoroo.andlib.service.ContextManager;
|
||||
import com.todoroo.andlib.utility.AndroidUtilities;
|
||||
import com.todoroo.andlib.utility.DateUtilities;
|
||||
import com.todoroo.andlib.utility.Preferences;
|
||||
import com.todoroo.astrid.data.Metadata;
|
||||
import com.todoroo.astrid.data.Task;
|
||||
import com.todoroo.astrid.gtasks.api.GtasksApiUtilities;
|
||||
import com.todoroo.astrid.gtasks.api.GtasksInvoker;
|
||||
import com.todoroo.astrid.gtasks.auth.GtasksTokenValidator;
|
||||
import com.todoroo.astrid.gtasks.sync.GtasksSyncService;
|
||||
import com.todoroo.astrid.service.TaskService;
|
||||
import com.todoroo.astrid.test.DatabaseTestCase;
|
||||
|
||||
public class GtasksSyncOnSaveTest extends DatabaseTestCase {
|
||||
|
||||
@Autowired TaskService taskService;
|
||||
@Autowired GtasksSyncService gtasksSyncService;
|
||||
@Autowired GtasksMetadataService gtasksMetadataService;
|
||||
@Autowired GtasksPreferenceService gtasksPreferenceService;
|
||||
|
||||
private static GtasksInvoker gtasksService;
|
||||
private boolean initialized = false;
|
||||
private boolean bypassTests = false;
|
||||
private static final String TEST_ACCOUNT = "sync_tester2@astrid.com";
|
||||
private static String DEFAULT_LIST = "@default";
|
||||
|
||||
//Have to wait a long time because sync on save happens in another thread--currently no way to know when finished
|
||||
private static final long TIME_TO_WAIT = 8000L;
|
||||
|
||||
|
||||
public void testSyncOnCreate() throws IOException {
|
||||
if(bypassTests) return;
|
||||
performBasicCreation("");
|
||||
}
|
||||
|
||||
private Task performBasicCreation(String appendToTitle) throws IOException {
|
||||
String title = "Created task" + appendToTitle;
|
||||
Task localTask = setupLocalTaskModel(title);
|
||||
taskService.save(localTask);
|
||||
|
||||
AndroidUtilities.sleepDeep(TIME_TO_WAIT);
|
||||
|
||||
com.google.api.services.tasks.model.Task remoteTask = getRemoteTaskForLocalId(localTask.getId());
|
||||
assertEquals(title, remoteTask.getTitle());
|
||||
return localTask;
|
||||
}
|
||||
|
||||
private Task setupLocalTaskModel(String title) {
|
||||
Task localTask = new Task();
|
||||
localTask.setTITLE(title);
|
||||
return localTask;
|
||||
}
|
||||
|
||||
private com.google.api.services.tasks.model.Task getRemoteTaskForLocalId(long localId) throws IOException {
|
||||
Metadata gtasksMetadata = gtasksMetadataService.getTaskMetadata(localId);
|
||||
assertNotNull(gtasksMetadata);
|
||||
com.google.api.services.tasks.model.Task remoteTask = gtasksService.getGtask(DEFAULT_LIST, gtasksMetadata.getValue(GtasksMetadata.ID));
|
||||
assertNotNull(remoteTask);
|
||||
return remoteTask;
|
||||
}
|
||||
|
||||
public void testSyncOnTitleUpdate() throws IOException {
|
||||
if(bypassTests) return;
|
||||
Task localTask = performBasicCreation("-title will change");
|
||||
|
||||
String newTitle = "Title has changed!";
|
||||
localTask.setTITLE(newTitle);
|
||||
taskService.save(localTask);
|
||||
|
||||
AndroidUtilities.sleepDeep(TIME_TO_WAIT);
|
||||
|
||||
com.google.api.services.tasks.model.Task remoteTask = getRemoteTaskForLocalId(localTask.getId());
|
||||
assertEquals(newTitle, remoteTask.getTitle());
|
||||
}
|
||||
|
||||
public void testSyncOnDueDateUpdate() throws IOException {
|
||||
if(bypassTests) return;
|
||||
Task localTask = performBasicCreation("-due date will change");
|
||||
|
||||
long dueDate = new Date(115, 2, 14).getTime();
|
||||
localTask.setDUE_DATE(dueDate);
|
||||
taskService.save(localTask);
|
||||
|
||||
AndroidUtilities.sleepDeep(TIME_TO_WAIT);
|
||||
|
||||
com.google.api.services.tasks.model.Task remoteTask = getRemoteTaskForLocalId(localTask.getId());
|
||||
assertEquals(dueDate, GtasksApiUtilities.gtasksDueTimeToUnixTime(remoteTask.getDue(), 0));
|
||||
}
|
||||
|
||||
public void testSyncOnNotesUpdate() throws IOException {
|
||||
if(bypassTests) return;
|
||||
Task localTask = performBasicCreation("-notes will change");
|
||||
|
||||
String notes = "Noted!";
|
||||
localTask.setNOTES(notes);
|
||||
taskService.save(localTask);
|
||||
|
||||
AndroidUtilities.sleepDeep(TIME_TO_WAIT);
|
||||
|
||||
com.google.api.services.tasks.model.Task remoteTask = getRemoteTaskForLocalId(localTask.getId());
|
||||
assertEquals(notes, remoteTask.getNotes());
|
||||
}
|
||||
|
||||
public void testSyncOnCompleted() throws IOException {
|
||||
if(bypassTests) return;
|
||||
Task localTask = performBasicCreation("-will be completed");
|
||||
|
||||
long completionDate = (DateUtilities.now() / 1000L) * 1000L;
|
||||
localTask.setCompletionDate(completionDate);
|
||||
taskService.save(localTask);
|
||||
|
||||
AndroidUtilities.sleepDeep(TIME_TO_WAIT);
|
||||
|
||||
com.google.api.services.tasks.model.Task remoteTask = getRemoteTaskForLocalId(localTask.getId());
|
||||
assertEquals("completed", remoteTask.getStatus());
|
||||
assertEquals(completionDate, GtasksApiUtilities.gtasksCompletedTimeToUnixTime(remoteTask.getCompleted(), 0));
|
||||
}
|
||||
|
||||
public void testSyncOnDeleted() throws IOException {
|
||||
if(bypassTests) return;
|
||||
Task localTask = performBasicCreation("-will be deleted");
|
||||
|
||||
long deletionDate = DateUtilities.now();
|
||||
localTask.setDELETION_DATE(deletionDate);
|
||||
taskService.save(localTask);
|
||||
|
||||
AndroidUtilities.sleepDeep(TIME_TO_WAIT);
|
||||
|
||||
com.google.api.services.tasks.model.Task remoteTask = getRemoteTaskForLocalId(localTask.getId());
|
||||
assertTrue(remoteTask.getDeleted());
|
||||
assertFalse(taskWithTitleExists(localTask.getTITLE()));
|
||||
}
|
||||
|
||||
private boolean taskWithTitleExists(String title) throws IOException {
|
||||
Tasks allTasks = gtasksService.getAllGtasksFromListId(DEFAULT_LIST, false, false, 0);
|
||||
List<com.google.api.services.tasks.model.Task> items = allTasks.getItems();
|
||||
if (items != null) {
|
||||
for (com.google.api.services.tasks.model.Task t : items) {
|
||||
if (t.getTitle().equals(title))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
if (!initialized) {
|
||||
initializeTestService();
|
||||
gtasksSyncService.initialize();
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
setupTestList();
|
||||
}
|
||||
|
||||
private void initializeTestService() throws Exception {
|
||||
GoogleAccountManager manager = new GoogleAccountManager(ContextManager.getContext());
|
||||
Account[] accounts = manager.getAccounts();
|
||||
|
||||
Account toUse = null;
|
||||
for (Account a : accounts) {
|
||||
if (a.name.equals(TEST_ACCOUNT)) {
|
||||
toUse = a;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (toUse == null) {
|
||||
if(accounts.length == 0) {
|
||||
bypassTests = true;
|
||||
return;
|
||||
}
|
||||
toUse = accounts[0];
|
||||
}
|
||||
|
||||
Preferences.setString(GtasksPreferenceService.PREF_USER_NAME, toUse.name);
|
||||
AccountManagerFuture<Bundle> accountManagerFuture = manager.manager.getAuthToken(toUse, "oauth2:https://www.googleapis.com/auth/tasks", true, null, null);
|
||||
|
||||
Bundle authTokenBundle = accountManagerFuture.getResult();
|
||||
if (authTokenBundle.containsKey(AccountManager.KEY_INTENT)) {
|
||||
Intent i = (Intent) authTokenBundle.get(AccountManager.KEY_INTENT);
|
||||
ContextManager.getContext().startActivity(i);
|
||||
return;
|
||||
}
|
||||
String authToken = authTokenBundle.getString(AccountManager.KEY_AUTHTOKEN);
|
||||
authToken = GtasksTokenValidator.validateAuthToken(getContext(), authToken);
|
||||
gtasksPreferenceService.setToken(authToken);
|
||||
|
||||
gtasksService = new GtasksInvoker(authToken);
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
private void setupTestList() throws Exception {
|
||||
Tasks defaultListTasks = gtasksService.getAllGtasksFromListId(DEFAULT_LIST, false, false, 0);
|
||||
List<com.google.api.services.tasks.model.Task> items = defaultListTasks.getItems();
|
||||
if (items != null) {
|
||||
for (com.google.api.services.tasks.model.Task t : items) {
|
||||
gtasksService.deleteGtask(DEFAULT_LIST, t.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.gtasks;
|
||||
|
||||
public class GtasksTestPreferenceService extends GtasksPreferenceService {
|
||||
|
||||
private boolean loggedIn = false;
|
||||
private long syncDate = 0;
|
||||
|
||||
public void setLoggedIn(boolean loggedIn) {
|
||||
this.loggedIn = loggedIn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLoggedIn() {
|
||||
return loggedIn;
|
||||
}
|
||||
|
||||
public void setSyncDate(long date) {
|
||||
syncDate = date;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLastSyncDate() {
|
||||
return syncDate;
|
||||
}
|
||||
}
|
||||
@ -1,404 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.sync.repeats;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import android.content.Intent;
|
||||
|
||||
import com.google.ical.values.Frequency;
|
||||
import com.google.ical.values.RRule;
|
||||
import com.google.ical.values.Weekday;
|
||||
import com.google.ical.values.WeekdayNum;
|
||||
import org.tasks.R;
|
||||
import com.todoroo.andlib.data.TodorooCursor;
|
||||
import com.todoroo.andlib.service.Autowired;
|
||||
import com.todoroo.andlib.sql.Query;
|
||||
import com.todoroo.andlib.utility.DateUtilities;
|
||||
import com.todoroo.andlib.utility.Preferences;
|
||||
import com.todoroo.astrid.api.AstridApiConstants;
|
||||
import com.todoroo.astrid.dao.MetadataDao;
|
||||
import com.todoroo.astrid.dao.TaskDao;
|
||||
import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
|
||||
import com.todoroo.astrid.data.SyncFlags;
|
||||
import com.todoroo.astrid.data.Task;
|
||||
import com.todoroo.astrid.repeats.RepeatTaskCompleteListener;
|
||||
import com.todoroo.astrid.test.DatabaseTestCase;
|
||||
import com.todoroo.astrid.utility.Flags;
|
||||
|
||||
abstract public class AbstractSyncRepeatTests<REMOTE_MODEL> extends DatabaseTestCase {
|
||||
|
||||
@Autowired protected TaskDao taskDao;
|
||||
|
||||
@Autowired protected MetadataDao metadataDao;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
Preferences.setStringFromInteger(R.string.p_default_urgency_key, 0);
|
||||
}
|
||||
|
||||
private void saveAndTriggerRepeatListener(Task task) {
|
||||
task.putTransitory(SyncFlags.ACTFM_SUPPRESS_OUTSTANDING_ENTRIES, true);
|
||||
task.putTransitory(SyncFlags.GTASKS_SUPPRESS_SYNC, true);
|
||||
if(task.isSaved())
|
||||
taskDao.saveExisting(task);
|
||||
else
|
||||
taskDao.createNew(task);
|
||||
|
||||
Intent intent = new Intent(AstridApiConstants.BROADCAST_EVENT_TASK_COMPLETED);
|
||||
intent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, task.getId());
|
||||
new RepeatTaskCompleteListener().onReceive(getContext(), intent);
|
||||
}
|
||||
|
||||
protected void waitAndSync() {
|
||||
// Subclasses can override this to insert sync functionality
|
||||
}
|
||||
|
||||
/**
|
||||
* @param t
|
||||
* @param expectedDueDate
|
||||
*/
|
||||
protected REMOTE_MODEL assertTaskExistsRemotely(Task t, long expectedDueDate) {
|
||||
// Subclasses can override this to check the existence of remote objects
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param t task
|
||||
*/
|
||||
protected void assertTaskCompletedRemotely(Task t) {
|
||||
// Subclasses can override this to check the status of the corresponding remote task
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param remoteModel
|
||||
*/
|
||||
protected long setCompletionDate(boolean completeBefore, Task t,
|
||||
REMOTE_MODEL remoteModel, long dueDate) {
|
||||
long completionDate = DateUtilities.now();
|
||||
t.setCompletionDate(completionDate);
|
||||
saveAndTriggerRepeatListener(t);
|
||||
return completionDate;
|
||||
}
|
||||
|
||||
protected void assertTimesMatch(long expectedTime, long newDueDate) {
|
||||
assertTrue(String.format("Expected %s, was %s", new Date(expectedTime), new Date(newDueDate)),
|
||||
Math.abs(expectedTime - newDueDate) <= 600000);
|
||||
// Allow a few minutes of variance to account for timing issues in tests
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests for no sync
|
||||
*/
|
||||
|
||||
public void testNoRepeat() {
|
||||
Task t = new Task();
|
||||
t.setTITLE("no repeat");
|
||||
taskDao.save(t);
|
||||
|
||||
t.setCompletionDate(DateUtilities.now());
|
||||
saveAndTriggerRepeatListener(t);
|
||||
|
||||
TodorooCursor<Task> cursor = taskDao.query(Query.select(Task.ID));
|
||||
try {
|
||||
assertEquals(1, cursor.getCount());
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
protected void testRepeating(boolean completeBefore, boolean fromCompletion,
|
||||
RRule rrule, Frequency frequency, String title) {
|
||||
Task t = new Task();
|
||||
t.setTITLE(title);
|
||||
long dueDate = DateUtilities.now() + ((completeBefore ? -1 : 1) * DateUtilities.ONE_DAY * 3);
|
||||
dueDate = Task.createDueDate(Task.URGENCY_SPECIFIC_DAY_TIME, (dueDate / 1000L) * 1000L); // Strip milliseconds
|
||||
|
||||
t.setDUE_DATE(dueDate);
|
||||
|
||||
if (rrule == null) {
|
||||
rrule = new RRule();
|
||||
rrule.setFreq(frequency);
|
||||
int interval = frequency.equals(Frequency.MINUTELY) ? 100: 2;
|
||||
rrule.setInterval(interval);
|
||||
}
|
||||
|
||||
String result = rrule.toIcal();
|
||||
if (fromCompletion)
|
||||
result = result + ";FROM=COMPLETION";
|
||||
|
||||
t.setRECURRENCE(rrule.toIcal());
|
||||
taskDao.save(t);
|
||||
|
||||
waitAndSync();
|
||||
t = taskDao.fetch(t.getId(), Task.PROPERTIES); // Refetch
|
||||
REMOTE_MODEL remoteModel = assertTaskExistsRemotely(t, dueDate);
|
||||
|
||||
long completionDate = setCompletionDate(completeBefore, t, remoteModel, dueDate);
|
||||
|
||||
waitAndSync();
|
||||
assertTaskCompletedRemotely(t);
|
||||
|
||||
TodorooCursor<Task> cursor = taskDao.query(Query.select(Task.PROPERTIES).where(TaskCriteria.notDeleted()));
|
||||
try {
|
||||
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
|
||||
Task task = new Task(cursor);
|
||||
System.err.println("Task: " + task.getTITLE() + ", due: " + task.getDUE_DATE());
|
||||
}
|
||||
assertEquals(1, cursor.getCount());
|
||||
cursor.moveToFirst();
|
||||
t.readFromCursor(cursor);
|
||||
|
||||
assertEquals(title, t.getTITLE());
|
||||
assertFalse(t.isCompleted());
|
||||
long newDueDate = t.getDUE_DATE();
|
||||
assertTrue(t.hasDueTime());
|
||||
|
||||
long fromDate = (fromCompletion? completionDate : dueDate);
|
||||
long expectedTime = computeNextDueDateFromDate(fromDate, rrule, fromCompletion);
|
||||
|
||||
assertTaskExistsRemotely(t, expectedTime);
|
||||
assertTimesMatch(expectedTime, newDueDate);
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
private long computeWeeklyCaseDueDate(long fromDate, RRule rrule, boolean fromCompletion) {
|
||||
long result = fromDate;
|
||||
Frequency frequency = rrule.getFreq();
|
||||
assertTrue(frequency.equals(Frequency.WEEKLY));
|
||||
List<WeekdayNum> weekdayNums = rrule.getByDay();
|
||||
|
||||
if (weekdayNums.size() == 0) {
|
||||
result += DateUtilities.ONE_WEEK * rrule.getInterval();
|
||||
return result;
|
||||
}
|
||||
HashSet<Weekday> weekdays = new HashSet<Weekday>();
|
||||
for (WeekdayNum curr : weekdayNums) {
|
||||
weekdays.add(curr.wday);
|
||||
}
|
||||
|
||||
Weekday[] allWeekdays = Weekday.values();
|
||||
// result -= DateUtilities.ONE_DAY;
|
||||
Date date = new Date(result);
|
||||
Weekday start = allWeekdays[date.getDay()];
|
||||
int i;
|
||||
for (i = 0; i < allWeekdays.length; i++) {
|
||||
if (start == allWeekdays[i]) break;
|
||||
}
|
||||
int index = i;
|
||||
int daysToAdd = 0;
|
||||
Weekday next = null;
|
||||
for (i = index + 1; i < allWeekdays.length; i++) {
|
||||
Weekday curr = allWeekdays[i];
|
||||
daysToAdd++;
|
||||
if (weekdays.contains(curr)) {
|
||||
next = curr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (next == null) {
|
||||
for (i = 0; i < index + 1; i++) {
|
||||
Weekday curr = allWeekdays[i];
|
||||
daysToAdd++;
|
||||
if (weekdays.contains(curr)) {
|
||||
next = curr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fromCompletion) {
|
||||
result += DateUtilities.ONE_WEEK * (rrule.getInterval() - 1);
|
||||
}
|
||||
result += DateUtilities.ONE_DAY * daysToAdd;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/** Advanced weekly repeating tests */
|
||||
protected long computeNextDueDateFromDate(long fromDate, RRule rrule, boolean fromCompletion) {
|
||||
long expectedTime = fromDate;
|
||||
Frequency frequency = rrule.getFreq();
|
||||
int interval = rrule.getInterval();
|
||||
if (frequency.equals(Frequency.MINUTELY)) {
|
||||
expectedTime += DateUtilities.ONE_MINUTE * interval;
|
||||
} else if (frequency.equals(Frequency.HOURLY)) {
|
||||
expectedTime += DateUtilities.ONE_HOUR * interval;
|
||||
} else if (frequency.equals(Frequency.DAILY)) {
|
||||
expectedTime += DateUtilities.ONE_DAY * interval;
|
||||
} else if (frequency.equals(Frequency.WEEKLY)) {
|
||||
expectedTime = computeWeeklyCaseDueDate(fromDate, rrule, fromCompletion);
|
||||
} else if (frequency.equals(Frequency.MONTHLY)) {
|
||||
Date originalDate = new Date(expectedTime);
|
||||
for (int i = 0; i < interval; i++) {
|
||||
int month = originalDate.getMonth();
|
||||
if (month == 11) { // Roll over the year and set the month to January
|
||||
originalDate.setYear(originalDate.getYear() + 1);
|
||||
originalDate.setMonth(0);
|
||||
} else {
|
||||
originalDate.setMonth(originalDate.getMonth() + 1);
|
||||
}
|
||||
}
|
||||
expectedTime = originalDate.getTime();
|
||||
} else if (frequency.equals(Frequency.YEARLY)) {
|
||||
Date originalCompleteDate = new Date(expectedTime);
|
||||
originalCompleteDate.setYear(originalCompleteDate.getYear() + interval);
|
||||
expectedTime = originalCompleteDate.getTime();
|
||||
}
|
||||
|
||||
return Task.createDueDate(Task.URGENCY_SPECIFIC_DAY_TIME, expectedTime);
|
||||
}
|
||||
|
||||
private void testFromDueDate(boolean completeBefore, Frequency frequency, String title) {
|
||||
testRepeating(completeBefore, false, null, frequency, title);
|
||||
}
|
||||
|
||||
private void testFromCompletionDate(boolean completeBefore, Frequency frequency, String title) {
|
||||
testRepeating(completeBefore, true, null, frequency, title);
|
||||
}
|
||||
|
||||
|
||||
/** Tests for repeating from due date */
|
||||
|
||||
public void testRepeatMinutelyFromDueDateCompleteBefore() {
|
||||
testFromDueDate(true, Frequency.MINUTELY, "minutely-before");
|
||||
}
|
||||
|
||||
public void testRepeatMinutelyFromDueDateCompleteAfter() {
|
||||
testFromDueDate(false, Frequency.MINUTELY, "minutely-after");
|
||||
}
|
||||
|
||||
public void testRepeatHourlyFromDueDateCompleteBefore() {
|
||||
testFromDueDate(true, Frequency.HOURLY, "hourly-before");
|
||||
}
|
||||
|
||||
public void testRepeatHourlyFromDueDateCompleteAfter() {
|
||||
testFromDueDate(false, Frequency.HOURLY, "hourly-after");
|
||||
}
|
||||
|
||||
public void testRepeatDailyFromDueDateCompleteBefore() {
|
||||
testFromDueDate(true, Frequency.DAILY, "daily-before");
|
||||
}
|
||||
|
||||
public void testRepeatDailyFromDueDateCompleteAfter() {
|
||||
testFromDueDate(false, Frequency.DAILY, "daily-after");
|
||||
}
|
||||
|
||||
public void testRepeatWeeklyFromDueDateCompleteBefore() {
|
||||
testFromDueDate(true, Frequency.WEEKLY, "weekly-before");
|
||||
}
|
||||
|
||||
public void testRepeatWeeklyFromDueDateCompleteAfter() {
|
||||
testFromDueDate(false, Frequency.WEEKLY, "weekly-after");
|
||||
}
|
||||
|
||||
public void testRepeatMonthlyFromDueDateCompleteBefore() {
|
||||
testFromDueDate(true, Frequency.MONTHLY, "monthly-before");
|
||||
}
|
||||
|
||||
public void testRepeatMonthlyFromDueDateCompleteAfter() {
|
||||
testFromDueDate(false, Frequency.MONTHLY, "monthly-after");
|
||||
}
|
||||
|
||||
public void testRepeatYearlyFromDueDateCompleteBefore() {
|
||||
testFromDueDate(true, Frequency.YEARLY, "yearly-before");
|
||||
}
|
||||
|
||||
public void testRepeatYearlyFromDueDateCompleteAfter() {
|
||||
testFromDueDate(false, Frequency.YEARLY, "yearly-after");
|
||||
}
|
||||
|
||||
|
||||
/** Tests for repeating from completionDate */
|
||||
|
||||
public void testRepeatMinutelyFromCompleteDateCompleteBefore() {
|
||||
testFromCompletionDate(true, Frequency.MINUTELY, "minutely-before");
|
||||
}
|
||||
|
||||
public void testRepeatMinutelyFromCompleteDateCompleteAfter() {
|
||||
testFromCompletionDate(false, Frequency.MINUTELY, "minutely-after");
|
||||
}
|
||||
|
||||
public void testRepeatHourlyFromCompleteDateCompleteBefore() {
|
||||
testFromCompletionDate(true, Frequency.HOURLY, "hourly-before");
|
||||
}
|
||||
|
||||
public void testRepeatHourlyFromCompleteDateCompleteAfter() {
|
||||
testFromCompletionDate(false, Frequency.HOURLY, "hourly-after");
|
||||
}
|
||||
|
||||
public void testRepeatDailyFromCompleteDateCompleteBefore() {
|
||||
testFromCompletionDate(true, Frequency.DAILY, "daily-before");
|
||||
}
|
||||
|
||||
public void testRepeatDailyFromCompleteDateCompleteAfter() {
|
||||
testFromCompletionDate(false, Frequency.DAILY, "daily-after");
|
||||
}
|
||||
|
||||
public void testRepeatWeeklyFromCompleteDateCompleteBefore() {
|
||||
testFromCompletionDate(true, Frequency.WEEKLY, "weekly-before");
|
||||
}
|
||||
|
||||
public void testRepeatWeeklyFromCompleteDateCompleteAfter() {
|
||||
testFromCompletionDate(false, Frequency.WEEKLY, "weekly-after");
|
||||
}
|
||||
|
||||
public void testRepeatMonthlyFromCompleteDateCompleteBefore() {
|
||||
testFromCompletionDate(true, Frequency.MONTHLY, "monthly-before");
|
||||
}
|
||||
|
||||
public void testRepeatMonthlyFromCompleteDateCompleteAfter() {
|
||||
testFromCompletionDate(false, Frequency.MONTHLY, "monthly-after");
|
||||
}
|
||||
|
||||
public void testRepeatYearlyFromCompleteDateCompleteBefore() {
|
||||
testFromCompletionDate(true, Frequency.YEARLY, "yearly-before");
|
||||
}
|
||||
|
||||
public void testRepeatYearlyFromCompleteDateCompleteAfter() {
|
||||
testFromCompletionDate(false, Frequency.YEARLY, "yearly-after");
|
||||
}
|
||||
|
||||
private void testAdvancedWeekly(boolean fromCompletion, boolean completeBefore, String title) {
|
||||
RRule rrule = new RRule();
|
||||
rrule.setFreq(Frequency.WEEKLY);
|
||||
|
||||
int interval = 1;
|
||||
rrule.setInterval(interval);
|
||||
List<WeekdayNum> weekdays = new ArrayList<WeekdayNum>();
|
||||
weekdays.add(new WeekdayNum(0, Weekday.MO));
|
||||
weekdays.add(new WeekdayNum(0, Weekday.WE));
|
||||
rrule.setByDay(weekdays);
|
||||
testRepeating(completeBefore, fromCompletion, rrule, Frequency.WEEKLY, title);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// disabled until test can be fixed
|
||||
public void testAdvancedRepeatWeeklyFromDueDateCompleteBefore() {
|
||||
testAdvancedWeekly(false, true, "advanced-weekly-before");
|
||||
}
|
||||
|
||||
public void testAdvancedRepeatWeeklyFromDueDateCompleteAfter() {
|
||||
testAdvancedWeekly(false, false, "advanced-weekly-after");
|
||||
}
|
||||
|
||||
public void testAdvancedRepeatWeeklyFromCompleteDateCompleteBefore() {
|
||||
testAdvancedWeekly(true, true, "advanced-weekly-before");
|
||||
}
|
||||
|
||||
public void testAdvancedRepeatWeeklyFromCompleteDateCompleteAfter() {
|
||||
testAdvancedWeekly(true, false, "advanced-weekly-after");
|
||||
}
|
||||
}
|
||||
@ -1,173 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.sync.repeats;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Semaphore;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.accounts.AccountManagerFuture;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.google.api.client.googleapis.extensions.android2.auth.GoogleAccountManager;
|
||||
import com.google.api.services.tasks.model.Tasks;
|
||||
import org.tasks.R;
|
||||
import com.todoroo.andlib.service.Autowired;
|
||||
import com.todoroo.andlib.service.ContextManager;
|
||||
import com.todoroo.andlib.utility.AndroidUtilities;
|
||||
import com.todoroo.andlib.utility.Preferences;
|
||||
import com.todoroo.astrid.data.Metadata;
|
||||
import com.todoroo.astrid.data.Task;
|
||||
import com.todoroo.astrid.gtasks.GtasksMetadata;
|
||||
import com.todoroo.astrid.gtasks.GtasksMetadataService;
|
||||
import com.todoroo.astrid.gtasks.GtasksPreferenceService;
|
||||
import com.todoroo.astrid.gtasks.api.GtasksApiUtilities;
|
||||
import com.todoroo.astrid.gtasks.api.GtasksInvoker;
|
||||
import com.todoroo.astrid.gtasks.auth.GtasksTokenValidator;
|
||||
import com.todoroo.astrid.gtasks.sync.GtasksSyncService;
|
||||
import com.todoroo.astrid.gtasks.sync.GtasksSyncV2Provider;
|
||||
import com.todoroo.astrid.service.MetadataService;
|
||||
import com.todoroo.astrid.sync.SyncResultCallbackAdapter;
|
||||
|
||||
public class RepeatTestsGtasksSync extends AbstractSyncRepeatTests<com.google.api.services.tasks.model.Task> {
|
||||
|
||||
@Autowired MetadataService metadataService;
|
||||
@Autowired GtasksMetadataService gtasksMetadataService;
|
||||
@Autowired GtasksPreferenceService gtasksPreferenceService;
|
||||
@Autowired GtasksSyncService gtasksSyncService;
|
||||
|
||||
private static final String TEST_ACCOUNT = "sync_tester2@astrid.com";
|
||||
public static final String DEFAULT_LIST = "@default";
|
||||
|
||||
private static boolean initialized = false;
|
||||
protected static GtasksInvoker gtasksService;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
Preferences.setStringFromInteger(R.string.p_default_urgency_key, 0);
|
||||
|
||||
if (!initialized) {
|
||||
initializeTestService();
|
||||
}
|
||||
gtasksSyncService.initialize();
|
||||
|
||||
setupTestList();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void waitAndSync() {
|
||||
AndroidUtilities.sleepDeep(3000L);
|
||||
final Semaphore sema = new Semaphore(0);
|
||||
GtasksSyncV2Provider.getInstance().synchronizeActiveTasks(true, new SyncResultCallbackAdapter() {
|
||||
@Override
|
||||
public void finished() {
|
||||
sema.release();
|
||||
}
|
||||
});
|
||||
try {
|
||||
sema.acquire();
|
||||
} catch (InterruptedException e) {
|
||||
fail("Interrupted while waiting for sync to finish");
|
||||
}
|
||||
AndroidUtilities.sleepDeep(3000L);
|
||||
gtasksSyncService.waitUntilEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected com.google.api.services.tasks.model.Task assertTaskExistsRemotely(Task t, long expectedRemoteTime) {
|
||||
Metadata metadata = gtasksMetadataService.getTaskMetadata(t.getId());
|
||||
assertNotNull(metadata);
|
||||
String listId = metadata.getValue(GtasksMetadata.LIST_ID);
|
||||
String taskId = metadata.getValue(GtasksMetadata.ID);
|
||||
com.google.api.services.tasks.model.Task remote = null;
|
||||
try {
|
||||
remote = gtasksService.getGtask(listId, taskId);
|
||||
} catch (IOException e){
|
||||
e.printStackTrace();
|
||||
fail("Exception in gtasks service");
|
||||
}
|
||||
assertNotNull(remote);
|
||||
assertEquals(t.getTITLE(), remote.getTitle());
|
||||
|
||||
Date expected = new Date(expectedRemoteTime);
|
||||
expected.setHours(0);
|
||||
expected.setMinutes(0);
|
||||
expected.setSeconds(0);
|
||||
|
||||
long gtasksTime = GtasksApiUtilities.gtasksDueTimeToUnixTime(remote.getDue(), 0);
|
||||
assertTimesMatch(expected.getTime(), gtasksTime);
|
||||
return remote;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assertTaskCompletedRemotely(Task t) {
|
||||
Metadata metadata = gtasksMetadataService.getTaskMetadata(t.getId());
|
||||
assertNotNull(metadata);
|
||||
String listId = metadata.getValue(GtasksMetadata.LIST_ID);
|
||||
String taskId = metadata.getValue(GtasksMetadata.ID);
|
||||
com.google.api.services.tasks.model.Task remote = null;
|
||||
try {
|
||||
remote = gtasksService.getGtask(listId, taskId);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
fail("Exception in gtasks service");
|
||||
}
|
||||
|
||||
assertNotNull(remote);
|
||||
assertEquals(t.getTITLE(), remote.getTitle());
|
||||
}
|
||||
|
||||
private void initializeTestService() throws Exception {
|
||||
GoogleAccountManager manager = new GoogleAccountManager(ContextManager.getContext());
|
||||
Account[] accounts = manager.getAccounts();
|
||||
|
||||
Account toUse = null;
|
||||
for (Account a : accounts) {
|
||||
if (a.name.equals(TEST_ACCOUNT)) {
|
||||
toUse = a;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (toUse == null) {
|
||||
if (accounts.length == 0) {
|
||||
return;
|
||||
}
|
||||
toUse = accounts[0];
|
||||
}
|
||||
|
||||
Preferences.setString(GtasksPreferenceService.PREF_USER_NAME, toUse.name);
|
||||
AccountManagerFuture<Bundle> accountManagerFuture = manager.manager.getAuthToken(toUse, "oauth2:https://www.googleapis.com/auth/tasks", true, null, null);
|
||||
|
||||
Bundle authTokenBundle = accountManagerFuture.getResult();
|
||||
if (authTokenBundle.containsKey(AccountManager.KEY_INTENT)) {
|
||||
Intent i = (Intent) authTokenBundle.get(AccountManager.KEY_INTENT);
|
||||
ContextManager.getContext().startActivity(i);
|
||||
return;
|
||||
}
|
||||
String authToken = authTokenBundle.getString(AccountManager.KEY_AUTHTOKEN);
|
||||
authToken = GtasksTokenValidator.validateAuthToken(getContext(), authToken);
|
||||
gtasksPreferenceService.setToken(authToken);
|
||||
|
||||
gtasksService = new GtasksInvoker(authToken);
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
private void setupTestList() throws Exception {
|
||||
Tasks defaultListTasks = gtasksService.getAllGtasksFromListId(DEFAULT_LIST, false, false, 0);
|
||||
List<com.google.api.services.tasks.model.Task> items = defaultListTasks.getItems();
|
||||
if (items != null) {
|
||||
for (com.google.api.services.tasks.model.Task t : items) {
|
||||
gtasksService.deleteGtask(DEFAULT_LIST, t.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,39 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.sync.repeats;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
||||
import com.google.ical.values.Frequency;
|
||||
import com.google.ical.values.RRule;
|
||||
import com.todoroo.andlib.utility.DateUtilities;
|
||||
import com.todoroo.astrid.data.Task;
|
||||
import com.todoroo.astrid.gtasks.api.GtasksApiUtilities;
|
||||
|
||||
public class RepeatTestsGtasksSyncRemote extends RepeatTestsGtasksSync {
|
||||
|
||||
// Test logic in superclass
|
||||
|
||||
@Override
|
||||
protected long setCompletionDate(boolean completeBefore, Task t,
|
||||
com.google.api.services.tasks.model.Task remoteModel, long dueDate) {
|
||||
long completionDate;
|
||||
if (completeBefore)
|
||||
completionDate = dueDate - DateUtilities.ONE_DAY;
|
||||
else
|
||||
completionDate = dueDate + DateUtilities.ONE_DAY;
|
||||
remoteModel.setCompleted(GtasksApiUtilities.unixTimeToGtasksCompletionTime(completionDate));
|
||||
remoteModel.setStatus("completed");
|
||||
try {
|
||||
gtasksService.updateGtask(DEFAULT_LIST, remoteModel);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
fail("Exception in gtasks service");
|
||||
}
|
||||
return completionDate;
|
||||
}
|
||||
}
|
||||
@ -1,68 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.test;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import com.todoroo.astrid.dao.Database;
|
||||
import com.todoroo.astrid.provider.Astrid3ContentProvider;
|
||||
import com.todoroo.astrid.service.AstridDependencyInjector;
|
||||
|
||||
/**
|
||||
* Test case that automatically sets up and tears down a test database
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
public class DatabaseTestCase extends TodorooTestCaseWithInjector {
|
||||
|
||||
static {
|
||||
AstridDependencyInjector.initialize();
|
||||
}
|
||||
|
||||
public static Database database = new TestDatabase();
|
||||
|
||||
@Override
|
||||
protected void addInjectables() {
|
||||
testInjector.addInjectable("database", database);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
// call upstream setup, which invokes dependency injector
|
||||
super.setUp();
|
||||
|
||||
// empty out test databases
|
||||
database.clear();
|
||||
database.openForWriting();
|
||||
|
||||
Astrid3ContentProvider.setDatabaseOverride(database);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to delete a database by name
|
||||
* @param database
|
||||
*/
|
||||
protected void deleteDatabase(String database) {
|
||||
File db = getContext().getDatabasePath(database);
|
||||
if(db.exists())
|
||||
db.delete();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
database.close();
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
public static class TestDatabase extends Database {
|
||||
@Override
|
||||
public String getName() {
|
||||
return "databasetest";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,53 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.test;
|
||||
|
||||
import com.todoroo.andlib.service.AbstractDependencyInjector;
|
||||
import com.todoroo.andlib.service.DependencyInjectionService;
|
||||
|
||||
|
||||
public class TestDependencyInjector extends AbstractDependencyInjector {
|
||||
|
||||
private String name;
|
||||
|
||||
public TestDependencyInjector(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void addInjectable(String field, Object injection) {
|
||||
injectables.put(field, injection);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addInjectables() {
|
||||
// do nothing, we populate injectables via the addInjectable method
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TestDI:" + name;
|
||||
}
|
||||
|
||||
// --- static stuff
|
||||
|
||||
/**
|
||||
* Install TestDependencyInjector above other injectors
|
||||
*/
|
||||
public synchronized static TestDependencyInjector initialize(String name) {
|
||||
TestDependencyInjector instance = new TestDependencyInjector(name);
|
||||
DependencyInjectionService.getInstance().addInjector(instance);
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an installed TestDependencyInjector
|
||||
* @param string
|
||||
*/
|
||||
public static void deinitialize(TestDependencyInjector instance) {
|
||||
DependencyInjectionService.getInstance().removeInjector(instance);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.test;
|
||||
|
||||
|
||||
/**
|
||||
* Utility methods used in unit tests
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
public class TestUtilities {
|
||||
|
||||
/**
|
||||
* Sleep, suppressing exceptions
|
||||
*
|
||||
* @param millis
|
||||
*/
|
||||
public static void sleepDeep(long millis) {
|
||||
try {
|
||||
Thread.sleep(millis);
|
||||
} catch (InterruptedException e) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,71 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.test;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import android.content.res.Configuration;
|
||||
import android.test.AndroidTestCase;
|
||||
import android.util.DisplayMetrics;
|
||||
|
||||
import com.todoroo.andlib.service.ContextManager;
|
||||
import com.todoroo.andlib.service.DependencyInjectionService;
|
||||
import com.todoroo.astrid.service.AstridDependencyInjector;
|
||||
|
||||
/**
|
||||
* Base test case for Astrid tests
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
public class TodorooTestCase extends AndroidTestCase {
|
||||
|
||||
static {
|
||||
AstridDependencyInjector.initialize();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
ContextManager.setContext(this.getContext());
|
||||
AstridDependencyInjector.flush();
|
||||
DependencyInjectionService.getInstance().inject(this);
|
||||
setLocale(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
setLocale(Locale.getDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
* Loop through each locale and call runnable
|
||||
* @param r
|
||||
*/
|
||||
public void forEachLocale(Runnable r) {
|
||||
Locale[] locales = Locale.getAvailableLocales();
|
||||
for(Locale locale : locales) {
|
||||
setLocale(locale);
|
||||
|
||||
r.run();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets locale
|
||||
* @param locale
|
||||
*/
|
||||
private void setLocale(Locale locale) {
|
||||
Locale.setDefault(locale);
|
||||
Configuration config = new Configuration();
|
||||
config.locale = locale;
|
||||
DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
|
||||
getContext().getResources().updateConfiguration(config, metrics);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,36 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.test;
|
||||
|
||||
|
||||
/**
|
||||
* Base test case for Astrid tests that need a separate injection context
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
abstract public class TodorooTestCaseWithInjector extends TodorooTestCase {
|
||||
|
||||
protected TestDependencyInjector testInjector;
|
||||
|
||||
abstract protected void addInjectables();
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
testInjector = TestDependencyInjector.initialize("test");
|
||||
addInjectables();
|
||||
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
|
||||
TestDependencyInjector.deinitialize(testInjector);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,246 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Zutubi Pty Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.zutubi.android.junitreport;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
|
||||
import junit.framework.AssertionFailedError;
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestListener;
|
||||
|
||||
import org.xmlpull.v1.XmlSerializer;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import android.util.Xml;
|
||||
|
||||
/**
|
||||
* Custom test listener that outputs test results to a single XML file. The file
|
||||
* uses a similar format the to Ant JUnit task XML formatter, with a couple of
|
||||
* caveats:
|
||||
* <ul>
|
||||
* <li>Multiple suites are all placed in a single file under a root
|
||||
* <testsuites> element.</li>
|
||||
* <li>Redundant information about the number of nested cases within a suite is
|
||||
* omitted.</li>
|
||||
* <li>Neither standard output nor system properties are included.</li>
|
||||
* </ul>
|
||||
* The differences mainly revolve around making this reporting as lightweight as
|
||||
* possible. The report is streamed as the tests run, making it impossible to,
|
||||
* e.g. include the case count in a <testsuite> element.
|
||||
*/
|
||||
public class JUnitReportListener implements TestListener {
|
||||
private static final String LOG_TAG = "JUnitReportListener";
|
||||
|
||||
private static final String ENCODING_UTF_8 = "utf-8";
|
||||
|
||||
private static final String TAG_SUITES = "testsuites";
|
||||
private static final String TAG_SUITE = "testsuite";
|
||||
private static final String TAG_CASE = "testcase";
|
||||
private static final String TAG_ERROR = "error";
|
||||
private static final String TAG_FAILURE = "failure";
|
||||
|
||||
private static final String ATTRIBUTE_NAME = "name";
|
||||
private static final String ATTRIBUTE_CLASS = "classname";
|
||||
private static final String ATTRIBUTE_TYPE = "type";
|
||||
private static final String ATTRIBUTE_MESSAGE = "message";
|
||||
private static final String ATTRIBUTE_TIME = "time";
|
||||
|
||||
// With thanks to org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.
|
||||
// Trimmed some entries, added others for Android.
|
||||
private static final String[] DEFAULT_TRACE_FILTERS = new String[] {
|
||||
"junit.framework.TestCase", "junit.framework.TestResult",
|
||||
"junit.framework.TestSuite",
|
||||
"junit.framework.Assert.", // don't filter AssertionFailure
|
||||
"java.lang.reflect.Method.invoke(", "sun.reflect.",
|
||||
// JUnit 4 support:
|
||||
"org.junit.", "junit.framework.JUnit4TestAdapter", " more",
|
||||
// Added for Android
|
||||
"android.test.", "android.app.Instrumentation",
|
||||
"java.lang.reflect.Method.invokeNative",
|
||||
};
|
||||
|
||||
private Context mContext;
|
||||
private String mReportFilePath;
|
||||
private boolean mFilterTraces;
|
||||
private FileOutputStream mOutputStream;
|
||||
private XmlSerializer mSerializer;
|
||||
private String mCurrentSuite;
|
||||
|
||||
// simple time tracking
|
||||
private boolean timeAlreadyWritten = false;
|
||||
private long testStart;
|
||||
|
||||
/**
|
||||
* Creates a new listener.
|
||||
*
|
||||
* @param context context of the target application under test
|
||||
* @param reportFilePath path of the report file to create (under the
|
||||
* context using {@link Context#openFileOutput(String, int)}).
|
||||
* @param filterTraces if true, stack traces will have common noise (e.g.
|
||||
* framework methods) omitted for clarity
|
||||
*/
|
||||
public JUnitReportListener(Context context, String reportFilePath, boolean filterTraces) {
|
||||
this.mContext = context;
|
||||
this.mReportFilePath = reportFilePath;
|
||||
this.mFilterTraces = filterTraces;
|
||||
}
|
||||
|
||||
public void startTest(Test test) {
|
||||
try {
|
||||
openIfRequired(test);
|
||||
|
||||
if (test instanceof TestCase) {
|
||||
TestCase testCase = (TestCase) test;
|
||||
checkForNewSuite(testCase);
|
||||
testStart = System.currentTimeMillis();
|
||||
timeAlreadyWritten = false;
|
||||
mSerializer.startTag("", TAG_CASE);
|
||||
mSerializer.attribute("", ATTRIBUTE_CLASS, mCurrentSuite);
|
||||
mSerializer.attribute("", ATTRIBUTE_NAME, testCase.getName());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(LOG_TAG, safeMessage(e));
|
||||
}
|
||||
}
|
||||
|
||||
private void checkForNewSuite(TestCase testCase) throws IOException {
|
||||
String suiteName = testCase.getClass().getName();
|
||||
if (mCurrentSuite == null || !mCurrentSuite.equals(suiteName)) {
|
||||
if (mCurrentSuite != null) {
|
||||
mSerializer.endTag("", TAG_SUITE);
|
||||
}
|
||||
|
||||
mSerializer.startTag("", TAG_SUITE);
|
||||
mSerializer.attribute("", ATTRIBUTE_NAME, suiteName);
|
||||
mCurrentSuite = suiteName;
|
||||
}
|
||||
}
|
||||
|
||||
private void openIfRequired(Test test) throws IOException {
|
||||
if (mOutputStream == null) {
|
||||
mOutputStream = mContext.openFileOutput(mReportFilePath, 0);
|
||||
mSerializer = Xml.newSerializer();
|
||||
mSerializer.setOutput(mOutputStream, ENCODING_UTF_8);
|
||||
mSerializer.startDocument(ENCODING_UTF_8, true);
|
||||
mSerializer.startTag("", TAG_SUITES);
|
||||
}
|
||||
}
|
||||
|
||||
public void addError(Test test, Throwable error) {
|
||||
addProblem(TAG_ERROR, error);
|
||||
}
|
||||
|
||||
public void addFailure(Test test, AssertionFailedError error) {
|
||||
addProblem(TAG_FAILURE, error);
|
||||
}
|
||||
|
||||
private void addProblem(String tag, Throwable error) {
|
||||
try {
|
||||
recordTestTime();
|
||||
|
||||
mSerializer.startTag("", tag);
|
||||
mSerializer.attribute("", ATTRIBUTE_MESSAGE, safeMessage(error));
|
||||
mSerializer.attribute("", ATTRIBUTE_TYPE, error.getClass().getName());
|
||||
StringWriter w = new StringWriter();
|
||||
error.printStackTrace(mFilterTraces ? new FilteringWriter(w) : new PrintWriter(w));
|
||||
mSerializer.text(w.toString());
|
||||
mSerializer.endTag("", tag);
|
||||
} catch (IOException e) {
|
||||
Log.e(LOG_TAG, safeMessage(e));
|
||||
}
|
||||
}
|
||||
|
||||
private void recordTestTime() throws IOException {
|
||||
if(!timeAlreadyWritten) {
|
||||
timeAlreadyWritten = true;
|
||||
mSerializer.attribute("", ATTRIBUTE_TIME,
|
||||
String.format("%.3f", (System.currentTimeMillis() - testStart) / 1000.));
|
||||
}
|
||||
}
|
||||
|
||||
public void endTest(Test test) {
|
||||
try {
|
||||
if (test instanceof TestCase) {
|
||||
recordTestTime();
|
||||
mSerializer.endTag("", TAG_CASE);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(LOG_TAG, safeMessage(e));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases all resources associated with this listener. Must be called
|
||||
* when the listener is finished with.
|
||||
*/
|
||||
public void close() {
|
||||
if (mSerializer != null) {
|
||||
try {
|
||||
if (mCurrentSuite != null) {
|
||||
mSerializer.endTag("", TAG_SUITE);
|
||||
}
|
||||
|
||||
mSerializer.endTag("", TAG_SUITES);
|
||||
mSerializer.endDocument();
|
||||
mSerializer = null;
|
||||
} catch (IOException e) {
|
||||
Log.e(LOG_TAG, safeMessage(e));
|
||||
}
|
||||
}
|
||||
|
||||
if (mOutputStream != null) {
|
||||
try {
|
||||
mOutputStream.close();
|
||||
mOutputStream = null;
|
||||
} catch (IOException e) {
|
||||
Log.e(LOG_TAG, safeMessage(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String safeMessage(Throwable error) {
|
||||
String message = error.getMessage();
|
||||
return error.getClass().getName() + ": " + (message == null ? "<null>" : message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around a print writer that filters out common noise from stack
|
||||
* traces, making it easier to see the actual failure.
|
||||
*/
|
||||
private static class FilteringWriter extends PrintWriter {
|
||||
public FilteringWriter(Writer out) {
|
||||
super(out);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void println(String s) {
|
||||
for (String filtered : DEFAULT_TRACE_FILTERS) {
|
||||
if (s.contains(filtered)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
super.println(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,98 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Zutubi Pty Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.zutubi.android.junitreport;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.test.AndroidTestRunner;
|
||||
import android.test.InstrumentationTestRunner;
|
||||
|
||||
/**
|
||||
* Custom test runner that adds a {@link JUnitReportListener} to the underlying
|
||||
* test runner in order to capture test results in an XML report. You may use
|
||||
* this class in place of {@link InstrumentationTestRunner} in your test
|
||||
* project's manifest, and/or specify it to your Ant build using the test.runner
|
||||
* property.
|
||||
* <p/>
|
||||
* This runner behaves identically to the default, with the added side-effect of
|
||||
* producing a JUnit XML report. The report format is similar to that produced
|
||||
* by the Ant JUnit task's XML formatter, making it compatible with existing
|
||||
* tools that can process that format. See {@link JUnitReportListener} for
|
||||
* further details.
|
||||
* <p/>
|
||||
* This runner accepts the following arguments:
|
||||
* <ul>
|
||||
* <li>reportFilePath: path of the file to write the XML report to, in the
|
||||
* target application's data area (default: junit-report.xml).</li>
|
||||
* <li>filterTraces: if true, stack traces in test failure reports will be
|
||||
* filtered to remove noise such as framework methods (default: true)</li>
|
||||
* </ul>
|
||||
* These arguments may be specified as follows:
|
||||
*
|
||||
* <pre>
|
||||
* {@code adb shell am instrument -w -e reportFile my-report-file.xml}
|
||||
* </pre>
|
||||
*/
|
||||
public class JUnitReportTestRunner extends InstrumentationTestRunner {
|
||||
/**
|
||||
* Path, relative to the target applications file root, at which to write the report file.
|
||||
*/
|
||||
private static final String ARG_REPORT_FILE_PATH = "reportFilePath";
|
||||
/**
|
||||
* If true, stack traces in the report will be filtered to remove common noise (e.g. framework
|
||||
* methods).
|
||||
*/
|
||||
private static final String ARG_FILTER_TRACES = "filterTraces";
|
||||
/**
|
||||
* Default path of the report file.
|
||||
*/
|
||||
private static final String DEFAULT_REPORT_FILE = "junit-report.xml";
|
||||
|
||||
private JUnitReportListener mListener;
|
||||
private String mReportFilePath;
|
||||
private boolean mFilterTraces = true;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle arguments) {
|
||||
if (arguments != null) {
|
||||
mReportFilePath = arguments.getString(ARG_REPORT_FILE_PATH);
|
||||
mFilterTraces = arguments.getBoolean(ARG_FILTER_TRACES, true);
|
||||
}
|
||||
|
||||
if (mReportFilePath == null) {
|
||||
mReportFilePath = DEFAULT_REPORT_FILE;
|
||||
}
|
||||
|
||||
super.onCreate(arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AndroidTestRunner getAndroidTestRunner() {
|
||||
AndroidTestRunner runner = new AndroidTestRunner();
|
||||
mListener = new JUnitReportListener(getTargetContext(), mReportFilePath, mFilterTraces);
|
||||
runner.addTestListener(mListener);
|
||||
return runner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish(int resultCode, Bundle results) {
|
||||
if (mListener != null) {
|
||||
mListener.close();
|
||||
}
|
||||
|
||||
super.finish(resultCode, results);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue