Initial checkin of AOSP Messaging app.
b/23110861 Change-Id: I9aa980d7569247d6b2ca78f5dcb4502e1eaadb8a
This commit is contained in:
@@ -0,0 +1,436 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* 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.android.messaging.datamodel.action;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.test.suitebuilder.annotation.MediumTest;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.messaging.BugleTestCase;
|
||||
import com.android.messaging.Factory;
|
||||
import com.android.messaging.FakeContext;
|
||||
import com.android.messaging.FakeContext.FakeContextHost;
|
||||
import com.android.messaging.FakeFactory;
|
||||
import com.android.messaging.datamodel.BugleServiceTestCase;
|
||||
import com.android.messaging.datamodel.DataModel;
|
||||
import com.android.messaging.datamodel.FakeDataModel;
|
||||
import com.android.messaging.datamodel.action.ActionMonitor.ActionCompletedListener;
|
||||
import com.android.messaging.datamodel.action.ActionMonitor.ActionExecutedListener;
|
||||
import com.android.messaging.datamodel.action.ActionTestHelpers.ResultTracker;
|
||||
import com.android.messaging.datamodel.action.ActionTestHelpers.StubBackgroundWorker;
|
||||
import com.android.messaging.datamodel.action.ActionTestHelpers.StubConnectivityUtil;
|
||||
import com.android.messaging.datamodel.action.ActionTestHelpers.StubLoader;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@MediumTest
|
||||
public class ActionServiceSystemTest extends BugleServiceTestCase<ActionServiceImpl>
|
||||
implements ActionCompletedListener, ActionExecutedListener, FakeContextHost {
|
||||
private static final String TAG = "ActionServiceSystemTest";
|
||||
|
||||
static {
|
||||
// Set flag during loading of test cases to prevent application initialization starting
|
||||
BugleTestCase.setTestsRunning();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActionSucceeded(final ActionMonitor monitor,
|
||||
final Action action, final Object data, final Object result) {
|
||||
final TestChatAction test = (TestChatAction) action;
|
||||
assertEquals("Expect correct action parameter", parameter, test.parameter);
|
||||
final ResultTracker tracker = (ResultTracker) data;
|
||||
tracker.completionResult = result;
|
||||
synchronized(tracker) {
|
||||
tracker.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActionFailed(final ActionMonitor monitor, final Action action,
|
||||
final Object data, final Object result) {
|
||||
final TestChatAction test = (TestChatAction) action;
|
||||
assertEquals("Expect correct action parameter", parameter, test.parameter);
|
||||
final ResultTracker tracker = (ResultTracker) data;
|
||||
tracker.completionResult = result;
|
||||
synchronized(tracker) {
|
||||
tracker.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActionExecuted(final ActionMonitor monitor, final Action action,
|
||||
final Object data, final Object result) {
|
||||
final TestChatAction test = (TestChatAction) action;
|
||||
assertEquals("Expect correct action parameter", parameter, test.parameter);
|
||||
final ResultTracker tracker = (ResultTracker) data;
|
||||
tracker.executionResult = result;
|
||||
}
|
||||
|
||||
public ActionServiceSystemTest() {
|
||||
super(ActionServiceImpl.class);
|
||||
}
|
||||
|
||||
public void testChatActionSucceeds() {
|
||||
final ResultTracker tracker = new ResultTracker();
|
||||
|
||||
final ActionService service = DataModel.get().getActionService();
|
||||
final TestChatActionMonitor monitor = new TestChatActionMonitor(null, tracker, this, this);
|
||||
final TestChatAction initial = new TestChatAction(monitor.getActionKey(), parameter);
|
||||
|
||||
assertNull("Expect completion result to start null", tracker.completionResult);
|
||||
assertNull("Expect execution result to start null", tracker.executionResult);
|
||||
|
||||
final Parcel parcel = Parcel.obtain();
|
||||
parcel.writeParcelable(initial, 0);
|
||||
parcel.setDataPosition(0);
|
||||
final TestChatAction action = parcel.readParcelable(mContext.getClassLoader());
|
||||
|
||||
synchronized(mWorker) {
|
||||
try {
|
||||
action.start(monitor);
|
||||
// Wait for callback across threads
|
||||
mWorker.wait(2000);
|
||||
} catch (final InterruptedException e) {
|
||||
assertTrue("Interrupted waiting for execution", false);
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals("Expect to see 1 server request queued", 1,
|
||||
mWorker.getRequestsMade().size());
|
||||
final Action request = mWorker.getRequestsMade().get(0);
|
||||
assertTrue("Expect Test type", request instanceof TestChatAction);
|
||||
|
||||
final Bundle response = new Bundle();
|
||||
response.putString(TestChatAction.RESPONSE_TEST, processResponseResult);
|
||||
synchronized(tracker) {
|
||||
try {
|
||||
request.markBackgroundWorkStarting();
|
||||
request.markBackgroundWorkQueued();
|
||||
|
||||
request.markBackgroundWorkStarting();
|
||||
request.markBackgroundCompletionQueued();
|
||||
service.handleResponseFromBackgroundWorker(request, response);
|
||||
// Wait for callback across threads
|
||||
tracker.wait(2000);
|
||||
} catch (final InterruptedException e) {
|
||||
assertTrue("Interrupted waiting for response processing", false);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
//assertEquals("Expect execution result set", executeActionResult, tracker.executionResult);
|
||||
assertEquals("Expect completion result set", processResponseResult,
|
||||
tracker.completionResult);
|
||||
}
|
||||
|
||||
public void testChatActionFails() {
|
||||
final ResultTracker tracker = new ResultTracker();
|
||||
|
||||
final ActionService service = DataModel.get().getActionService();
|
||||
final TestChatActionMonitor monitor = new TestChatActionMonitor(null, tracker, this, this);
|
||||
final TestChatAction action = new TestChatAction(monitor.getActionKey(), parameter);
|
||||
|
||||
assertNull("Expect completion result to start null", tracker.completionResult);
|
||||
assertNull("Expect execution result to start null", tracker.executionResult);
|
||||
|
||||
synchronized(mWorker) {
|
||||
try {
|
||||
action.start(monitor);
|
||||
// Wait for callback across threads
|
||||
mWorker.wait(2000);
|
||||
} catch (final InterruptedException e) {
|
||||
assertTrue("Interrupted waiting for requests", false);
|
||||
}
|
||||
}
|
||||
|
||||
final ArrayList<Intent> intents = mContext.extractIntents();
|
||||
assertNotNull(intents);
|
||||
assertEquals("Expect to see one intent", intents.size(), 1);
|
||||
|
||||
assertEquals("Expect to see 1 server request queued", 1,
|
||||
mWorker.getRequestsMade().size());
|
||||
final Action request = mWorker.getRequestsMade().get(0);
|
||||
assertTrue("Expect Test type", request instanceof TestChatAction);
|
||||
|
||||
synchronized(tracker) {
|
||||
try {
|
||||
request.markBackgroundWorkStarting();
|
||||
request.markBackgroundWorkQueued();
|
||||
|
||||
request.markBackgroundWorkStarting();
|
||||
request.markBackgroundCompletionQueued();
|
||||
service.handleFailureFromBackgroundWorker(request, new Exception("It went wrong"));
|
||||
// Wait for callback across threads
|
||||
tracker.wait(2000);
|
||||
} catch (final InterruptedException e) {
|
||||
assertTrue("Interrupted waiting for response processing", false);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
//assertEquals("Expect execution result set", executeActionResult, tracker.executionResult);
|
||||
assertEquals("Expect completion result set", processFailureResult,
|
||||
tracker.completionResult);
|
||||
}
|
||||
|
||||
public void testChatActionNoMonitor() {
|
||||
final ActionService service = DataModel.get().getActionService();
|
||||
final TestChatAction action =
|
||||
new TestChatAction(Action.generateUniqueActionKey(null), parameter);
|
||||
|
||||
synchronized(mWorker) {
|
||||
try {
|
||||
action.start();
|
||||
// Wait for callback across threads
|
||||
mWorker.wait(2000);
|
||||
} catch (final InterruptedException e) {
|
||||
assertTrue("Interrupted waiting for execution", false);
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals("Expect to see 1 server request queued", 1,
|
||||
mWorker.getRequestsMade().size());
|
||||
Action request = mWorker.getRequestsMade().get(0);
|
||||
assertTrue("Expect Test type", request instanceof TestChatAction);
|
||||
|
||||
final Bundle response = new Bundle();
|
||||
response.putString(TestChatAction.RESPONSE_TEST, processResponseResult);
|
||||
synchronized(mWorker) {
|
||||
try {
|
||||
service.handleResponseFromBackgroundWorker(request, response);
|
||||
// Wait for callback across threads
|
||||
mWorker.wait(2000);
|
||||
} catch (final InterruptedException e) {
|
||||
assertTrue("Interrupted waiting for response processing", false);
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals("Expect to see second server request queued",
|
||||
2, mWorker.getRequestsMade().size());
|
||||
request = mWorker.getRequestsMade().get(1);
|
||||
assertTrue("Expect other type",
|
||||
request instanceof TestChatActionOther);
|
||||
}
|
||||
|
||||
public void testChatActionUnregisterListener() {
|
||||
final ResultTracker tracker = new ResultTracker();
|
||||
|
||||
final ActionService service = DataModel.get().getActionService();
|
||||
final TestChatActionMonitor monitor = new TestChatActionMonitor(null, tracker, this, this);
|
||||
final TestChatAction action = new TestChatAction(monitor.getActionKey(), parameter);
|
||||
|
||||
assertNull("Expect completion result to start null", tracker.completionResult);
|
||||
assertNull("Expect execution result to start null", tracker.executionResult);
|
||||
|
||||
synchronized(mWorker) {
|
||||
try {
|
||||
action.start(monitor);
|
||||
// Wait for callback across threads
|
||||
mWorker.wait(2000);
|
||||
} catch (final InterruptedException e) {
|
||||
assertTrue("Interrupted waiting for execution", false);
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals("Expect to see 1 server request queued", 1,
|
||||
mWorker.getRequestsMade().size());
|
||||
final Action request = mWorker.getRequestsMade().get(0);
|
||||
assertTrue("Expect Test type", request instanceof TestChatAction);
|
||||
|
||||
monitor.unregister();
|
||||
|
||||
final Bundle response = new Bundle();
|
||||
synchronized(mWorker) {
|
||||
try {
|
||||
request.markBackgroundWorkStarting();
|
||||
request.markBackgroundWorkQueued();
|
||||
|
||||
request.markBackgroundWorkStarting();
|
||||
request.markBackgroundCompletionQueued();
|
||||
service.handleResponseFromBackgroundWorker(request, response);
|
||||
// Wait for callback across threads
|
||||
mWorker.wait(2000);
|
||||
} catch (final InterruptedException e) {
|
||||
assertTrue("Interrupted waiting for response processing", false);
|
||||
}
|
||||
}
|
||||
|
||||
//assertEquals("Expect execution result set", executeActionResult, tracker.executionResult);
|
||||
assertEquals("Expect completion never called", null, tracker.completionResult);
|
||||
}
|
||||
|
||||
StubBackgroundWorker mWorker;
|
||||
FakeContext mContext;
|
||||
StubLoader mLoader;
|
||||
|
||||
private static final String parameter = "parameter";
|
||||
private static final Object executeActionResult = "executeActionResult";
|
||||
private static final String processResponseResult = "processResponseResult";
|
||||
private static final Object processFailureResult = "processFailureResult";
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
Log.d(TAG, "ChatActionTest setUp");
|
||||
|
||||
mContext = new FakeContext(getContext(), this);
|
||||
mWorker = new StubBackgroundWorker();
|
||||
FakeFactory.registerWithFakeContext(getContext(), mContext)
|
||||
.withDataModel(new FakeDataModel(mContext)
|
||||
.withBackgroundWorkerForActionService(mWorker)
|
||||
.withActionService(new ActionService())
|
||||
.withConnectivityUtil(new StubConnectivityUtil(mContext)));
|
||||
|
||||
mLoader = new StubLoader();
|
||||
setContext(Factory.get().getApplicationContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServiceClassName() {
|
||||
return ActionServiceImpl.class.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startServiceForStub(final Intent intent) {
|
||||
this.startService(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartCommandForStub(final Intent intent, final int flags, final int startId) {
|
||||
this.getService().onStartCommand(intent, flags, startId);
|
||||
}
|
||||
|
||||
public static class TestChatAction extends Action implements Parcelable {
|
||||
public static String RESPONSE_TEST = "response_test";
|
||||
public static String KEY_PARAMETER = "parameter";
|
||||
|
||||
protected TestChatAction(final String key, final String parameter) {
|
||||
super(key);
|
||||
this.actionParameters.putString(KEY_PARAMETER, parameter);
|
||||
// Cache parameter as a member variable
|
||||
this.parameter = parameter;
|
||||
}
|
||||
|
||||
// An example parameter
|
||||
public final String parameter;
|
||||
|
||||
/**
|
||||
* Process the action locally - runs on datamodel service thread
|
||||
*/
|
||||
@Override
|
||||
protected Object executeAction() {
|
||||
requestBackgroundWork();
|
||||
return executeActionResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the response from the server - runs on datamodel service thread
|
||||
*/
|
||||
@Override
|
||||
protected Object processBackgroundResponse(final Bundle response) {
|
||||
requestBackgroundWork(new TestChatActionOther(null, parameter));
|
||||
return response.get(RESPONSE_TEST);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called in case of failures when sending requests - runs on datamodel service thread
|
||||
*/
|
||||
@Override
|
||||
protected Object processBackgroundFailure() {
|
||||
return processFailureResult;
|
||||
}
|
||||
|
||||
private TestChatAction(final Parcel in) {
|
||||
super(in);
|
||||
// Cache parameter as a member variable
|
||||
parameter = actionParameters.getString(KEY_PARAMETER);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<TestChatAction> CREATOR
|
||||
= new Parcelable.Creator<TestChatAction>() {
|
||||
@Override
|
||||
public TestChatAction createFromParcel(final Parcel in) {
|
||||
return new TestChatAction(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TestChatAction[] newArray(final int size) {
|
||||
return new TestChatAction[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void writeToParcel(final Parcel parcel, final int flags) {
|
||||
writeActionToParcel(parcel, flags);
|
||||
}
|
||||
}
|
||||
|
||||
public static class TestChatActionOther extends Action implements Parcelable {
|
||||
protected TestChatActionOther(final String key, final String parameter) {
|
||||
super(generateUniqueActionKey(key));
|
||||
this.parameter = parameter;
|
||||
}
|
||||
|
||||
public final String parameter;
|
||||
|
||||
private TestChatActionOther(final Parcel in) {
|
||||
super(in);
|
||||
parameter = in.readString();
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<TestChatActionOther> CREATOR
|
||||
= new Parcelable.Creator<TestChatActionOther>() {
|
||||
@Override
|
||||
public TestChatActionOther createFromParcel(final Parcel in) {
|
||||
return new TestChatActionOther(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TestChatActionOther[] newArray(final int size) {
|
||||
return new TestChatActionOther[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void writeToParcel(final Parcel parcel, final int flags) {
|
||||
writeActionToParcel(parcel, flags);
|
||||
parcel.writeString(parameter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An operation that notifies a listener upon completion
|
||||
*/
|
||||
public static class TestChatActionMonitor extends ActionMonitor {
|
||||
/**
|
||||
* Create action state wrapping an BlockUserAction instance
|
||||
* @param account - account in which to block the user
|
||||
* @param baseKey - suggested action key from BlockUserAction
|
||||
* @param data - optional action specific data that is handed back to listener
|
||||
* @param listener - action completed listener
|
||||
*/
|
||||
public TestChatActionMonitor(final String baseKey, final Object data,
|
||||
final ActionCompletedListener completed, final ActionExecutedListener executed) {
|
||||
super(STATE_CREATED, Action.generateUniqueActionKey(baseKey), data);
|
||||
setCompletedListener(completed);
|
||||
setExecutedListener(executed);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* 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.android.messaging.datamodel.action;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.Looper;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.Process;
|
||||
import android.test.suitebuilder.annotation.MediumTest;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.messaging.Factory;
|
||||
import com.android.messaging.FakeContext;
|
||||
import com.android.messaging.FakeContext.FakeContextHost;
|
||||
import com.android.messaging.FakeFactory;
|
||||
import com.android.messaging.datamodel.BugleServiceTestCase;
|
||||
import com.android.messaging.datamodel.FakeDataModel;
|
||||
import com.android.messaging.datamodel.action.ActionMonitor.ActionCompletedListener;
|
||||
import com.android.messaging.datamodel.action.ActionMonitor.ActionStateChangedListener;
|
||||
import com.android.messaging.datamodel.action.ActionTestHelpers.ResultTracker;
|
||||
import com.android.messaging.datamodel.action.ActionTestHelpers.StubBackgroundWorker;
|
||||
import com.android.messaging.datamodel.action.ActionTestHelpers.StubConnectivityUtil;
|
||||
import com.android.messaging.datamodel.action.ActionTestHelpers.StubLoader;
|
||||
import com.android.messaging.util.WakeLockHelper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@MediumTest
|
||||
public class ActionServiceTest extends BugleServiceTestCase<ActionServiceImpl>
|
||||
implements FakeContextHost, ActionStateChangedListener, ActionCompletedListener {
|
||||
private static final String TAG = "ActionServiceTest";
|
||||
|
||||
@Override
|
||||
public void onActionStateChanged(final Action action, final int state) {
|
||||
mStates.add(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActionSucceeded(final ActionMonitor monitor,
|
||||
final Action action, final Object data, final Object result) {
|
||||
final TestChatAction test = (TestChatAction) action;
|
||||
assertNotSame(test.dontRelyOnMe, dontRelyOnMe);
|
||||
// This will be true - but only briefly
|
||||
assertEquals(test.dontRelyOnMe, becauseIChange);
|
||||
|
||||
final ResultTracker tracker = (ResultTracker) data;
|
||||
tracker.completionResult = result;
|
||||
synchronized(tracker) {
|
||||
tracker.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActionFailed(final ActionMonitor monitor, final Action action,
|
||||
final Object data, final Object result) {
|
||||
final TestChatAction test = (TestChatAction) action;
|
||||
assertNotSame(test.dontRelyOnMe, dontRelyOnMe);
|
||||
// This will be true - but only briefly
|
||||
assertEquals(test.dontRelyOnMe, becauseIChange);
|
||||
|
||||
final ResultTracker tracker = (ResultTracker) data;
|
||||
tracker.completionResult = result;
|
||||
synchronized(tracker) {
|
||||
tracker.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For a dummy action verify that the service intent is constructed and queued correctly and
|
||||
* that when that intent is processed it actually executes the action.
|
||||
*/
|
||||
public void testChatServiceCreatesIntentAndExecutesAction() {
|
||||
final ResultTracker tracker = new ResultTracker();
|
||||
|
||||
final TestChatActionMonitor monitor = new TestChatActionMonitor(null, tracker, this, this);
|
||||
final TestChatAction action = new TestChatAction(monitor.getActionKey(), parameter);
|
||||
|
||||
action.dontRelyOnMe = dontRelyOnMe;
|
||||
assertFalse("Expect service initially stopped", mServiceStarted);
|
||||
|
||||
action.start(monitor);
|
||||
|
||||
assertTrue("Expect service started", mServiceStarted);
|
||||
|
||||
final ArrayList<Intent> intents = mContext.extractIntents();
|
||||
assertNotNull(intents);
|
||||
assertEquals("Expect to see 1 server request queued", 1, intents.size());
|
||||
final Intent intent = intents.get(0);
|
||||
assertEquals("Check pid", intent.getIntExtra(WakeLockHelper.EXTRA_CALLING_PID, 0),
|
||||
Process.myPid());
|
||||
assertEquals("Check opcode", intent.getIntExtra(ActionServiceImpl.EXTRA_OP_CODE, 0),
|
||||
ActionServiceImpl.OP_START_ACTION);
|
||||
assertTrue("Check wakelock held", ActionServiceImpl.sWakeLock.isHeld(intent));
|
||||
|
||||
synchronized(tracker) {
|
||||
try {
|
||||
this.startService(intent);
|
||||
// Wait for callback across threads
|
||||
tracker.wait(2000);
|
||||
} catch (final InterruptedException e) {
|
||||
assertTrue("Interrupted waiting for response processing", false);
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals("Expect three states ", mStates.size(), 3);
|
||||
assertEquals("State-0 should be STATE_QUEUED", (int)mStates.get(0),
|
||||
ActionMonitor.STATE_QUEUED);
|
||||
assertEquals("State-1 should be STATE_EXECUTING", (int)mStates.get(1),
|
||||
ActionMonitor.STATE_EXECUTING);
|
||||
assertEquals("State-2 should be STATE_COMPLETE", (int)mStates.get(2),
|
||||
ActionMonitor.STATE_COMPLETE);
|
||||
// TODO: Should find a way to reliably wait, this is a bit of a hack
|
||||
if (ActionServiceImpl.sWakeLock.isHeld(intent)) {
|
||||
Log.d(TAG, "ActionServiceTest: waiting for wakelock release");
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (final InterruptedException e) {
|
||||
}
|
||||
}
|
||||
assertFalse("Check wakelock released", ActionServiceImpl.sWakeLock.isHeld(intent));
|
||||
}
|
||||
|
||||
StubBackgroundWorker mWorker;
|
||||
FakeContext mContext;
|
||||
StubLoader mLoader;
|
||||
ActionService mService;
|
||||
|
||||
ArrayList<Integer> mStates;
|
||||
|
||||
private static final String parameter = "parameter";
|
||||
private static final Object dontRelyOnMe = "dontRelyOnMe";
|
||||
private static final Object becauseIChange = "becauseIChange";
|
||||
private static final Object executeActionResult = "executeActionResult";
|
||||
private static final Object processResponseResult = "processResponseResult";
|
||||
private static final Object processFailureResult = "processFailureResult";
|
||||
|
||||
public ActionServiceTest() {
|
||||
super(ActionServiceImpl.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
Log.d(TAG, "ChatActionTest setUp");
|
||||
|
||||
sLooper = Looper.myLooper();
|
||||
|
||||
mWorker = new StubBackgroundWorker();
|
||||
mContext = new FakeContext(getContext(), this);
|
||||
FakeFactory.registerWithFakeContext(getContext(),mContext)
|
||||
.withDataModel(new FakeDataModel(mContext)
|
||||
.withBackgroundWorkerForActionService(mWorker)
|
||||
.withActionService(new ActionService())
|
||||
.withConnectivityUtil(new StubConnectivityUtil(mContext)));
|
||||
|
||||
mStates = new ArrayList<Integer>();
|
||||
setContext(Factory.get().getApplicationContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServiceClassName() {
|
||||
return ActionServiceImpl.class.getName();
|
||||
}
|
||||
|
||||
boolean mServiceStarted = false;
|
||||
|
||||
@Override
|
||||
public void startServiceForStub(final Intent intent) {
|
||||
// Do nothing until later
|
||||
assertFalse(mServiceStarted);
|
||||
mServiceStarted = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartCommandForStub(final Intent intent, final int flags, final int startId) {
|
||||
assertTrue(mServiceStarted);
|
||||
}
|
||||
|
||||
private static Looper sLooper;
|
||||
public static void assertRunsOnOtherThread() {
|
||||
assertTrue (Looper.myLooper() != Looper.getMainLooper());
|
||||
assertTrue (Looper.myLooper() != sLooper);
|
||||
}
|
||||
|
||||
public static class TestChatAction extends Action implements Parcelable {
|
||||
public static String RESPONSE_TEST = "response_test";
|
||||
public static String KEY_PARAMETER = "parameter";
|
||||
|
||||
protected TestChatAction(final String key, final String parameter) {
|
||||
super(key);
|
||||
this.actionParameters.putString(KEY_PARAMETER, parameter);
|
||||
}
|
||||
|
||||
transient Object dontRelyOnMe;
|
||||
|
||||
/**
|
||||
* Process the action locally - runs on service thread
|
||||
*/
|
||||
@Override
|
||||
protected Object executeAction() {
|
||||
this.dontRelyOnMe = becauseIChange;
|
||||
assertRunsOnOtherThread();
|
||||
return executeActionResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the response from the server - runs on service thread
|
||||
*/
|
||||
@Override
|
||||
protected Object processBackgroundResponse(final Bundle response) {
|
||||
assertRunsOnOtherThread();
|
||||
return processResponseResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called in case of failures when sending requests - runs on service thread
|
||||
*/
|
||||
@Override
|
||||
protected Object processBackgroundFailure() {
|
||||
assertRunsOnOtherThread();
|
||||
return processFailureResult;
|
||||
}
|
||||
|
||||
private TestChatAction(final Parcel in) {
|
||||
super(in);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<TestChatAction> CREATOR
|
||||
= new Parcelable.Creator<TestChatAction>() {
|
||||
@Override
|
||||
public TestChatAction createFromParcel(final Parcel in) {
|
||||
return new TestChatAction(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TestChatAction[] newArray(final int size) {
|
||||
return new TestChatAction[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void writeToParcel(final Parcel parcel, final int flags) {
|
||||
writeActionToParcel(parcel, flags);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An operation that notifies a listener upon state changes, execution and completion
|
||||
*/
|
||||
public static class TestChatActionMonitor extends ActionMonitor {
|
||||
public TestChatActionMonitor(final String baseKey, final Object data,
|
||||
final ActionStateChangedListener listener, final ActionCompletedListener executed) {
|
||||
super(STATE_CREATED, Action.generateUniqueActionKey(baseKey), data);
|
||||
setStateChangedListener(listener);
|
||||
setCompletedListener(executed);
|
||||
assertEquals("Initial state should be STATE_CREATED", mState, STATE_CREATED);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,324 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* 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.android.messaging.datamodel.action;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.test.suitebuilder.annotation.MediumTest;
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
|
||||
import com.android.messaging.BugleTestCase;
|
||||
import com.android.messaging.FakeFactory;
|
||||
import com.android.messaging.datamodel.DataModelImpl;
|
||||
import com.android.messaging.datamodel.action.ActionTestHelpers.StubChatActionMonitor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@MediumTest
|
||||
public class ActionTest extends BugleTestCase {
|
||||
private static final String parameter = "parameter";
|
||||
private static final Object executeActionResult = "executeActionResult";
|
||||
private static final Object processResponseResult = "processResponseResult";
|
||||
private static final Object processFailureResult = "processFailureResult";
|
||||
|
||||
private static final String mActionKey = "TheActionKey";
|
||||
private static final Object mData = "PrivateData";
|
||||
private StubChatActionMonitor mMonitor;
|
||||
private TestChatAction mAction;
|
||||
|
||||
private ArrayList<StubChatActionMonitor.StateTransition> mTransitions;
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
FakeFactory.register(getTestContext())
|
||||
.withDataModel(new DataModelImpl(getContext()));
|
||||
|
||||
mMonitor = new StubChatActionMonitor(ActionMonitor.STATE_CREATED, mActionKey,
|
||||
mData);
|
||||
mAction = new TestChatAction(mActionKey, parameter);
|
||||
mTransitions = mMonitor.getTransitions();
|
||||
}
|
||||
|
||||
private void verifyState(final int count, final int from, final int to) {
|
||||
assertEquals(to, mMonitor.getState());
|
||||
assertEquals(mTransitions.size(), count);
|
||||
verifyTransition(count-1, from , to);
|
||||
}
|
||||
|
||||
private void verifyTransition(final int index, final int from, final int to) {
|
||||
assertTrue(mTransitions.size() > index);
|
||||
assertEquals(mAction, mTransitions.get(index).action);
|
||||
assertEquals(from, mTransitions.get(index).from);
|
||||
assertEquals(to, mTransitions.get(index).to);
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testActionStartTransitionsCorrectly() {
|
||||
mMonitor.setState(ActionMonitor.STATE_CREATED);
|
||||
|
||||
ActionMonitor.registerActionMonitor(mAction.actionKey, mMonitor);
|
||||
assertTrue(ActionMonitor.sActionMonitors.containsKey(mAction.actionKey));
|
||||
assertTrue(ActionMonitor.sActionMonitors.containsValue(mMonitor));
|
||||
assertEquals(ActionMonitor.sActionMonitors.get(mAction.actionKey), mMonitor);
|
||||
|
||||
mAction.markStart();
|
||||
assertEquals("After start state: STATE_QUEUED", ActionMonitor.STATE_QUEUED,
|
||||
mMonitor.getState());
|
||||
verifyState(1, ActionMonitor.STATE_CREATED, ActionMonitor.STATE_QUEUED);
|
||||
|
||||
ActionMonitor.unregisterActionMonitor(mAction.actionKey, mMonitor);
|
||||
|
||||
assertFalse(ActionMonitor.sActionMonitors.containsKey(mAction.actionKey));
|
||||
assertFalse(ActionMonitor.sActionMonitors.containsValue(mMonitor));
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testActionStartAssertsFromIncorrectState() {
|
||||
mMonitor.setState(ActionMonitor.STATE_UNDEFINED);
|
||||
|
||||
ActionMonitor.registerActionMonitor(mAction.actionKey, mMonitor);
|
||||
assertTrue(ActionMonitor.sActionMonitors.containsKey(mAction.actionKey));
|
||||
assertTrue(ActionMonitor.sActionMonitors.containsValue(mMonitor));
|
||||
assertEquals(ActionMonitor.sActionMonitors.get(mAction.actionKey), mMonitor);
|
||||
|
||||
try {
|
||||
mAction.markStart();
|
||||
fail("Expect assertion when starting from STATE_UNDEFINED");
|
||||
} catch (final IllegalStateException ex){
|
||||
}
|
||||
ActionMonitor.unregisterActionMonitor(mAction.actionKey, mMonitor);
|
||||
|
||||
assertFalse(ActionMonitor.sActionMonitors.containsKey(mAction.actionKey));
|
||||
assertFalse(ActionMonitor.sActionMonitors.containsValue(mMonitor));
|
||||
}
|
||||
|
||||
public void testActionTransitionsEndToEndWithRequests() {
|
||||
assertEquals("Start state: STATE_CREATED", ActionMonitor.STATE_CREATED,
|
||||
mMonitor.getState());
|
||||
|
||||
ActionMonitor.registerActionMonitor(mAction.actionKey, mMonitor);
|
||||
assertTrue(ActionMonitor.sActionMonitors.containsKey(mAction.actionKey));
|
||||
assertTrue(ActionMonitor.sActionMonitors.containsValue(mMonitor));
|
||||
assertEquals(ActionMonitor.sActionMonitors.get(mAction.actionKey), mMonitor);
|
||||
|
||||
mAction.markStart();
|
||||
|
||||
verifyState(1, ActionMonitor.STATE_CREATED, ActionMonitor.STATE_QUEUED);
|
||||
|
||||
mAction.markBeginExecute();
|
||||
|
||||
verifyState(2, ActionMonitor.STATE_QUEUED, ActionMonitor.STATE_EXECUTING);
|
||||
|
||||
final Object result = mAction.executeAction();
|
||||
mAction.requestBackgroundWork();
|
||||
|
||||
assertEquals("Check executeAction result", result, executeActionResult);
|
||||
|
||||
mAction.markEndExecute(result);
|
||||
|
||||
verifyState(3, ActionMonitor.STATE_EXECUTING,
|
||||
ActionMonitor.STATE_BACKGROUND_ACTIONS_QUEUED);
|
||||
|
||||
mAction.markBackgroundWorkStarting();
|
||||
|
||||
verifyState(4, ActionMonitor.STATE_BACKGROUND_ACTIONS_QUEUED,
|
||||
ActionMonitor.STATE_EXECUTING_BACKGROUND_ACTION);
|
||||
|
||||
mAction.markBackgroundWorkQueued();
|
||||
|
||||
verifyState(5, ActionMonitor.STATE_EXECUTING_BACKGROUND_ACTION,
|
||||
ActionMonitor.STATE_BACKGROUND_ACTIONS_QUEUED);
|
||||
|
||||
mAction.markBackgroundWorkStarting();
|
||||
|
||||
verifyState(6, ActionMonitor.STATE_BACKGROUND_ACTIONS_QUEUED,
|
||||
ActionMonitor.STATE_EXECUTING_BACKGROUND_ACTION);
|
||||
|
||||
final Bundle response = null;
|
||||
|
||||
mAction.markBackgroundCompletionQueued();
|
||||
|
||||
verifyState(7, ActionMonitor.STATE_EXECUTING_BACKGROUND_ACTION,
|
||||
ActionMonitor.STATE_BACKGROUND_COMPLETION_QUEUED);
|
||||
|
||||
assertTrue(ActionMonitor.sActionMonitors.containsKey(mAction.actionKey));
|
||||
assertTrue(ActionMonitor.sActionMonitors.containsValue(mMonitor));
|
||||
assertEquals(ActionMonitor.sActionMonitors.get(mAction.actionKey), mMonitor);
|
||||
|
||||
mAction.processBackgroundWorkResponse(response);
|
||||
|
||||
verifyTransition(7, ActionMonitor.STATE_BACKGROUND_COMPLETION_QUEUED,
|
||||
ActionMonitor.STATE_PROCESSING_BACKGROUND_RESPONSE);
|
||||
|
||||
verifyState(9, ActionMonitor.STATE_PROCESSING_BACKGROUND_RESPONSE,
|
||||
ActionMonitor.STATE_COMPLETE);
|
||||
|
||||
assertFalse(ActionMonitor.sActionMonitors.containsKey(mAction.actionKey));
|
||||
assertFalse(ActionMonitor.sActionMonitors.containsValue(mMonitor));
|
||||
}
|
||||
|
||||
public void testActionTransitionsEndToEndFailsRequests() {
|
||||
assertEquals("Start state: STATE_CREATED", ActionMonitor.STATE_CREATED,
|
||||
mMonitor.getState());
|
||||
|
||||
ActionMonitor.registerActionMonitor(mAction.actionKey, mMonitor);
|
||||
assertTrue(ActionMonitor.sActionMonitors.containsKey(mAction.actionKey));
|
||||
assertTrue(ActionMonitor.sActionMonitors.containsValue(mMonitor));
|
||||
assertEquals(ActionMonitor.sActionMonitors.get(mAction.actionKey), mMonitor);
|
||||
|
||||
mAction.markStart();
|
||||
|
||||
verifyState(1, ActionMonitor.STATE_CREATED, ActionMonitor.STATE_QUEUED);
|
||||
|
||||
mAction.markBeginExecute();
|
||||
|
||||
verifyState(2, ActionMonitor.STATE_QUEUED, ActionMonitor.STATE_EXECUTING);
|
||||
|
||||
final Object result = mAction.executeAction();
|
||||
mAction.requestBackgroundWork();
|
||||
|
||||
assertEquals("Check executeAction result", result, executeActionResult);
|
||||
|
||||
mAction.markEndExecute(result);
|
||||
|
||||
verifyState(3, ActionMonitor.STATE_EXECUTING,
|
||||
ActionMonitor.STATE_BACKGROUND_ACTIONS_QUEUED);
|
||||
|
||||
mAction.markBackgroundWorkStarting();
|
||||
|
||||
verifyState(4, ActionMonitor.STATE_BACKGROUND_ACTIONS_QUEUED,
|
||||
ActionMonitor.STATE_EXECUTING_BACKGROUND_ACTION);
|
||||
|
||||
mAction.markBackgroundWorkQueued();
|
||||
|
||||
verifyState(5, ActionMonitor.STATE_EXECUTING_BACKGROUND_ACTION,
|
||||
ActionMonitor.STATE_BACKGROUND_ACTIONS_QUEUED);
|
||||
|
||||
mAction.markBackgroundWorkStarting();
|
||||
|
||||
verifyState(6, ActionMonitor.STATE_BACKGROUND_ACTIONS_QUEUED,
|
||||
ActionMonitor.STATE_EXECUTING_BACKGROUND_ACTION);
|
||||
|
||||
assertTrue(ActionMonitor.sActionMonitors.containsKey(mAction.actionKey));
|
||||
assertTrue(ActionMonitor.sActionMonitors.containsValue(mMonitor));
|
||||
assertEquals(ActionMonitor.sActionMonitors.get(mAction.actionKey), mMonitor);
|
||||
|
||||
mAction.processBackgroundWorkFailure();
|
||||
|
||||
verifyState(7, ActionMonitor.STATE_EXECUTING_BACKGROUND_ACTION,
|
||||
ActionMonitor.STATE_COMPLETE);
|
||||
|
||||
assertFalse(ActionMonitor.sActionMonitors.containsKey(mAction.actionKey));
|
||||
assertFalse(ActionMonitor.sActionMonitors.containsValue(mMonitor));
|
||||
}
|
||||
|
||||
public void testActionTransitionsEndToEndNoRequests() {
|
||||
assertEquals("Start state: STATE_CREATED", ActionMonitor.STATE_CREATED,
|
||||
mMonitor.getState());
|
||||
|
||||
ActionMonitor.registerActionMonitor(mAction.actionKey, mMonitor);
|
||||
assertTrue(ActionMonitor.sActionMonitors.containsKey(mAction.actionKey));
|
||||
assertTrue(ActionMonitor.sActionMonitors.containsValue(mMonitor));
|
||||
assertEquals(ActionMonitor.sActionMonitors.get(mAction.actionKey), mMonitor);
|
||||
|
||||
mAction.markStart();
|
||||
|
||||
verifyState(1, ActionMonitor.STATE_CREATED, ActionMonitor.STATE_QUEUED);
|
||||
|
||||
mAction.markBeginExecute();
|
||||
|
||||
verifyState(2, ActionMonitor.STATE_QUEUED, ActionMonitor.STATE_EXECUTING);
|
||||
|
||||
final Object result = mAction.executeAction();
|
||||
|
||||
assertEquals("Check executeAction result", result, executeActionResult);
|
||||
|
||||
assertTrue(ActionMonitor.sActionMonitors.containsKey(mAction.actionKey));
|
||||
assertTrue(ActionMonitor.sActionMonitors.containsValue(mMonitor));
|
||||
assertEquals(ActionMonitor.sActionMonitors.get(mAction.actionKey), mMonitor);
|
||||
|
||||
mAction.markEndExecute(result);
|
||||
|
||||
verifyState(3, ActionMonitor.STATE_EXECUTING,
|
||||
ActionMonitor.STATE_COMPLETE);
|
||||
|
||||
assertFalse(ActionMonitor.sActionMonitors.containsKey(mAction.actionKey));
|
||||
assertFalse(ActionMonitor.sActionMonitors.containsValue(mMonitor));
|
||||
}
|
||||
|
||||
public static class TestChatAction extends Action implements Parcelable {
|
||||
protected TestChatAction(final String key, final String parameter) {
|
||||
super(key);
|
||||
this.parameter = parameter;
|
||||
}
|
||||
|
||||
public final String parameter;
|
||||
|
||||
/**
|
||||
* Process the action locally - runs on service thread
|
||||
*/
|
||||
@Override
|
||||
protected Object executeAction() {
|
||||
assertEquals("Check parameter", parameter, ActionTest.parameter);
|
||||
return executeActionResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the response from the server - runs on service thread
|
||||
*/
|
||||
@Override
|
||||
protected Object processBackgroundResponse(final Bundle response) {
|
||||
assertEquals("Check parameter", parameter, ActionTest.parameter);
|
||||
return processResponseResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called in case of failures when sending requests - runs on service thread
|
||||
*/
|
||||
@Override
|
||||
protected Object processBackgroundFailure() {
|
||||
assertEquals("Check parameter", parameter, ActionTest.parameter);
|
||||
return processFailureResult;
|
||||
}
|
||||
|
||||
private TestChatAction(final Parcel in) {
|
||||
super(in);
|
||||
parameter = in.readString();
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<TestChatAction> CREATOR
|
||||
= new Parcelable.Creator<TestChatAction>() {
|
||||
@Override
|
||||
public TestChatAction createFromParcel(final Parcel in) {
|
||||
return new TestChatAction(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TestChatAction[] newArray(final int size) {
|
||||
return new TestChatAction[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void writeToParcel(final Parcel parcel, final int flags) {
|
||||
writeActionToParcel(parcel, flags);
|
||||
parcel.writeString(parameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* 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.android.messaging.datamodel.action;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.ContentObserver;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.android.messaging.util.ConnectivityUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ActionTestHelpers {
|
||||
private static final String TAG = "DataModelTestHelpers";
|
||||
|
||||
static class StubLoader extends ContentObserver {
|
||||
ArrayList<Uri> mUriList = new ArrayList<Uri>();
|
||||
|
||||
StubLoader() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
mUriList.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChange(final boolean selfChange) {
|
||||
// Handle change.
|
||||
mUriList.add(null);
|
||||
}
|
||||
|
||||
// Implement the onChange(boolean, Uri) method to take advantage of the new Uri argument.
|
||||
// Only supported on platform 16 and above...
|
||||
@Override
|
||||
public void onChange(final boolean selfChange, final Uri uri) {
|
||||
// Handle change.
|
||||
mUriList.add(uri);
|
||||
}
|
||||
}
|
||||
|
||||
static class StubBackgroundWorker extends BackgroundWorker {
|
||||
public StubBackgroundWorker() {
|
||||
super();
|
||||
mActions = new ArrayList<Action>();
|
||||
}
|
||||
|
||||
ArrayList<Action> mActions;
|
||||
public ArrayList<Action> getRequestsMade() {
|
||||
return mActions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void queueBackgroundWork(final List<Action> actions) {
|
||||
mActions.addAll(actions);
|
||||
|
||||
synchronized(this) {
|
||||
this.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class ResultTracker {
|
||||
public Object executionResult;
|
||||
public Object completionResult;
|
||||
}
|
||||
|
||||
static class StubChatActionMonitor extends ActionMonitor {
|
||||
static public class StateTransition {
|
||||
Action action;
|
||||
int from;
|
||||
int to;
|
||||
public StateTransition(final Action action, final int from, final int to) {
|
||||
this.action = action;
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
}
|
||||
}
|
||||
|
||||
private final ArrayList<StateTransition> mTransitions;
|
||||
public ArrayList<StateTransition> getTransitions() {
|
||||
return mTransitions;
|
||||
}
|
||||
|
||||
protected StubChatActionMonitor(final int initialState, final String actionKey,
|
||||
final Object data) {
|
||||
super(initialState, actionKey, data);
|
||||
mTransitions = new ArrayList<StateTransition>();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateState(final Action action, final int expectedState,
|
||||
final int state) {
|
||||
mTransitions.add(new StateTransition(action, mState, state));
|
||||
super.updateState(action, expectedState, state);
|
||||
}
|
||||
|
||||
public void setState(final int state) {
|
||||
mState = state;
|
||||
}
|
||||
|
||||
public int getState() {
|
||||
return mState;
|
||||
}
|
||||
}
|
||||
|
||||
public static class StubActionService extends ActionService {
|
||||
public static class StubActionServiceCallLog {
|
||||
public final Action action;
|
||||
public final Action request;
|
||||
public final Bundle response;
|
||||
public final Exception exception;
|
||||
public final Action update;
|
||||
|
||||
public StubActionServiceCallLog(final Action action,
|
||||
final Action request,
|
||||
final Bundle response,
|
||||
final Exception exception,
|
||||
final Action update) {
|
||||
this.action = action;
|
||||
this.request = request;
|
||||
this.response = response;
|
||||
this.exception = exception;
|
||||
this.update = update;
|
||||
}
|
||||
}
|
||||
|
||||
private final ArrayList<StubActionServiceCallLog> mServiceCalls =
|
||||
new ArrayList<StubActionServiceCallLog>();
|
||||
|
||||
public ArrayList<StubActionServiceCallLog> getCalls() {
|
||||
return mServiceCalls;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startAction(final Action action) {
|
||||
mServiceCalls.add(new StubActionServiceCallLog(action, null, null, null, null));
|
||||
synchronized(this) {
|
||||
this.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleResponseFromBackgroundWorker(final Action request,
|
||||
final Bundle response) {
|
||||
mServiceCalls.add(new StubActionServiceCallLog(null, request, response, null, null));
|
||||
synchronized(this) {
|
||||
this.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleFailureFromBackgroundWorker(final Action request,
|
||||
final Exception exception) {
|
||||
mServiceCalls.add(new StubActionServiceCallLog(null, request, null, exception, null));
|
||||
synchronized(this) {
|
||||
this.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class StubConnectivityUtil extends ConnectivityUtil {
|
||||
public StubConnectivityUtil(final Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerForSignalStrength() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterForSignalStrength() {
|
||||
}
|
||||
}
|
||||
}
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* 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.android.messaging.datamodel.action;
|
||||
|
||||
import android.content.pm.ProviderInfo;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.test.mock.MockContentProvider;
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
|
||||
import com.android.messaging.BugleTestCase;
|
||||
import com.android.messaging.FakeContext;
|
||||
import com.android.messaging.FakeFactory;
|
||||
import com.android.messaging.datamodel.BugleDatabaseOperations;
|
||||
import com.android.messaging.datamodel.DataModel;
|
||||
import com.android.messaging.datamodel.DatabaseWrapper;
|
||||
import com.android.messaging.datamodel.FakeDataModel;
|
||||
import com.android.messaging.datamodel.MessagingContentProvider;
|
||||
import com.android.messaging.datamodel.action.ActionTestHelpers.StubActionService;
|
||||
import com.android.messaging.datamodel.action.ActionTestHelpers.StubActionService.StubActionServiceCallLog;
|
||||
import com.android.messaging.datamodel.action.GetOrCreateConversationAction.GetOrCreateConversationActionListener;
|
||||
import com.android.messaging.datamodel.action.GetOrCreateConversationAction.GetOrCreateConversationActionMonitor;
|
||||
import com.android.messaging.datamodel.data.ParticipantData;
|
||||
import com.android.messaging.datamodel.data.TestDataFactory;
|
||||
import com.android.messaging.sms.MmsUtils;
|
||||
|
||||
import org.mockito.Mock;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@SmallTest
|
||||
public class GetOrCreateConversationActionTest extends BugleTestCase {
|
||||
|
||||
@Mock GetOrCreateConversationActionListener mockListener;
|
||||
|
||||
public void testGetOrCreateConversation() {
|
||||
final DatabaseWrapper db = DataModel.get().getDatabase();
|
||||
|
||||
final ArrayList<String> recipients = new ArrayList<String>();
|
||||
recipients.add("5551234567");
|
||||
recipients.add("5551234568");
|
||||
|
||||
// Generate a list of partially formed participants
|
||||
final ArrayList<ParticipantData> participants = new
|
||||
ArrayList<ParticipantData>();
|
||||
|
||||
|
||||
for (final String recipient : recipients) {
|
||||
participants.add(ParticipantData.getFromRawPhoneBySystemLocale(recipient));
|
||||
}
|
||||
|
||||
// Test that we properly stubbed the SMS provider to return a thread id
|
||||
final long threadId = MmsUtils.getOrCreateThreadId(mContext, recipients);
|
||||
assertEquals(TestDataFactory.SMS_MMS_THREAD_ID_CURSOR_VALUE, threadId);
|
||||
|
||||
final String blankId = BugleDatabaseOperations.getExistingConversation(db, threadId, false);
|
||||
assertNull("Conversation already exists", blankId);
|
||||
|
||||
ArrayList<StubActionServiceCallLog> calls = mService.getCalls();
|
||||
|
||||
GetOrCreateConversationActionMonitor monitor =
|
||||
GetOrCreateConversationAction.getOrCreateConversation(participants, null,
|
||||
mockListener);
|
||||
|
||||
assertEquals("Failed to start service once for action", calls.size(), 1);
|
||||
assertTrue("Action not GetOrCreateConversationAction", calls.get(0).action instanceof
|
||||
GetOrCreateConversationAction);
|
||||
|
||||
GetOrCreateConversationAction action = (GetOrCreateConversationAction)
|
||||
calls.get(0).action;
|
||||
|
||||
Object result = action.executeAction();
|
||||
|
||||
assertTrue(result instanceof String);
|
||||
|
||||
// Make sure that we created a new conversation
|
||||
assertEquals(TestDataFactory.NUM_TEST_CONVERSATIONS+1, Integer.parseInt((String)result));
|
||||
|
||||
// Now get the conversation that we just created again
|
||||
monitor = GetOrCreateConversationAction.getOrCreateConversation(participants, null,
|
||||
mockListener);
|
||||
|
||||
calls = mService.getCalls();
|
||||
assertEquals("Failed to start service for second action", calls.size(), 2);
|
||||
assertTrue("Action not GetOrCreateConversationAction", calls.get(1).action instanceof
|
||||
GetOrCreateConversationAction);
|
||||
action = (GetOrCreateConversationAction)calls.get(1).action;
|
||||
result = action.executeAction();
|
||||
|
||||
assertTrue(result instanceof String);
|
||||
|
||||
final String conversationId = (String) result;
|
||||
|
||||
// Make sure that we found the same conversation id
|
||||
assertEquals(TestDataFactory.NUM_TEST_CONVERSATIONS+1, Integer.parseInt((String)result));
|
||||
|
||||
final ArrayList<ParticipantData> conversationParticipants =
|
||||
BugleDatabaseOperations.getParticipantsForConversation(db, conversationId);
|
||||
|
||||
assertEquals("Participant count mismatch", recipients.size(),
|
||||
conversationParticipants.size());
|
||||
for(final ParticipantData participant : conversationParticipants) {
|
||||
assertTrue(recipients.contains(participant.getSendDestination()));
|
||||
}
|
||||
|
||||
final Uri conversationParticipantsUri =
|
||||
MessagingContentProvider.buildConversationParticipantsUri(conversationId);
|
||||
final Cursor cursor = mContext.getContentResolver().query(conversationParticipantsUri,
|
||||
ParticipantData.ParticipantsQuery.PROJECTION, null, null, null);
|
||||
|
||||
int countSelf = 0;
|
||||
while(cursor.moveToNext()) {
|
||||
final ParticipantData participant = ParticipantData.getFromCursor(cursor);
|
||||
if (participant.isSelf()) {
|
||||
countSelf++;
|
||||
} else {
|
||||
assertTrue(recipients.contains(participant.getSendDestination()));
|
||||
}
|
||||
}
|
||||
cursor.close();
|
||||
assertEquals("Expect one self participant in conversations", 1, countSelf);
|
||||
assertEquals("Cursor count mismatch", recipients.size(), cursor.getCount() - countSelf);
|
||||
|
||||
final String realId = BugleDatabaseOperations.getExistingConversation(db, threadId, false);
|
||||
assertEquals("Conversation already exists", realId, conversationId);
|
||||
}
|
||||
|
||||
private FakeContext mContext;
|
||||
private StubActionService mService;
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
mContext = new FakeContext(getTestContext());
|
||||
|
||||
final MockContentProvider mockProvider = new MockContentProvider() {
|
||||
@Override
|
||||
public Cursor query(final Uri uri, final String[] projection, final String selection,
|
||||
final String[] selectionArgs, final String sortOrder) {
|
||||
return TestDataFactory.getSmsMmsThreadIdCursor();
|
||||
}
|
||||
};
|
||||
|
||||
mContext.addContentProvider("mms-sms", mockProvider);
|
||||
final MessagingContentProvider provider = new MessagingContentProvider();
|
||||
final ProviderInfo providerInfo = new ProviderInfo();
|
||||
providerInfo.authority = MessagingContentProvider.AUTHORITY;
|
||||
provider.attachInfo(mContext, providerInfo);
|
||||
mContext.addContentProvider(MessagingContentProvider.AUTHORITY, provider);
|
||||
|
||||
mService = new StubActionService();
|
||||
final FakeDataModel fakeDataModel = new FakeDataModel(mContext)
|
||||
.withActionService(mService);
|
||||
FakeFactory.registerWithFakeContext(getTestContext(), mContext)
|
||||
.withDataModel(fakeDataModel);
|
||||
provider.setDatabaseForTest(fakeDataModel.getDatabase());
|
||||
}
|
||||
}
|
||||
+482
@@ -0,0 +1,482 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* 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.android.messaging.datamodel.action;
|
||||
|
||||
import android.content.ContentProvider;
|
||||
import android.content.pm.ProviderInfo;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.android.messaging.BugleTestCase;
|
||||
import com.android.messaging.FakeContext;
|
||||
import com.android.messaging.FakeFactory;
|
||||
import com.android.messaging.datamodel.BugleDatabaseOperations;
|
||||
import com.android.messaging.datamodel.DataModel;
|
||||
import com.android.messaging.datamodel.DatabaseHelper;
|
||||
import com.android.messaging.datamodel.DatabaseHelper.ConversationColumns;
|
||||
import com.android.messaging.datamodel.DatabaseWrapper;
|
||||
import com.android.messaging.datamodel.FakeDataModel;
|
||||
import com.android.messaging.datamodel.MediaScratchFileProvider;
|
||||
import com.android.messaging.datamodel.MessagingContentProvider;
|
||||
import com.android.messaging.datamodel.action.ActionTestHelpers.StubActionService;
|
||||
import com.android.messaging.datamodel.action.ActionTestHelpers.StubActionService.StubActionServiceCallLog;
|
||||
import com.android.messaging.datamodel.action.ActionTestHelpers.StubConnectivityUtil;
|
||||
import com.android.messaging.datamodel.action.ReadDraftDataAction.ReadDraftDataActionListener;
|
||||
import com.android.messaging.datamodel.data.MessageData;
|
||||
import com.android.messaging.datamodel.data.MessagePartData;
|
||||
import com.android.messaging.datamodel.data.ParticipantData;
|
||||
import com.android.messaging.util.ContentType;
|
||||
|
||||
import org.mockito.Mock;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
|
||||
@SmallTest
|
||||
public class ReadWriteDraftMessageActionTest extends BugleTestCase {
|
||||
|
||||
@Mock ReadDraftDataActionListener mockListener;
|
||||
|
||||
// TODO: Add test cases
|
||||
// 1. Make sure drafts can include attachments and multiple parts
|
||||
// 2. Make sure attachments get cleaned up appropriately
|
||||
// 3. Make sure messageId and partIds not reused (currently each draft is a new message).
|
||||
public void testWriteDraft() {
|
||||
final String draftMessage = "draftMessage";
|
||||
final long threadId = 1234567;
|
||||
final boolean senderBlocked = false;
|
||||
final String participantNumber = "5551234567";
|
||||
|
||||
final DatabaseWrapper db = DataModel.get().getDatabase();
|
||||
|
||||
final String conversationId = getOrCreateConversation(db, participantNumber, threadId,
|
||||
senderBlocked);
|
||||
final String selfId = getOrCreateSelfId(db);
|
||||
|
||||
// Should clear/stub DB
|
||||
final ArrayList<StubActionServiceCallLog> calls = mService.getCalls();
|
||||
|
||||
final MessageData message = MessageData.createDraftSmsMessage(conversationId, selfId,
|
||||
draftMessage);
|
||||
|
||||
WriteDraftMessageAction.writeDraftMessage(conversationId, message);
|
||||
|
||||
assertEquals("Failed to start service once for action", calls.size(), 1);
|
||||
assertTrue("Action not SaveDraftMessageAction",
|
||||
calls.get(0).action instanceof WriteDraftMessageAction);
|
||||
|
||||
final Action save = calls.get(0).action;
|
||||
|
||||
final Object result = save.executeAction();
|
||||
|
||||
assertTrue("Expect row number string as result", result instanceof String);
|
||||
final String messageId = (String) result;
|
||||
|
||||
// Should check DB
|
||||
final MessageData actual = BugleDatabaseOperations.readMessage(db, messageId);
|
||||
assertNotNull("Database missing draft", actual);
|
||||
assertEquals("Draft text changed", draftMessage, actual.getMessageText());
|
||||
}
|
||||
|
||||
private static String getOrCreateSelfId(final DatabaseWrapper db) {
|
||||
db.beginTransaction();
|
||||
final String selfId = BugleDatabaseOperations.getOrCreateParticipantInTransaction(db,
|
||||
ParticipantData.getSelfParticipant(ParticipantData.DEFAULT_SELF_SUB_ID));
|
||||
db.setTransactionSuccessful();
|
||||
db.endTransaction();
|
||||
return selfId;
|
||||
}
|
||||
|
||||
private static String getOrCreateConversation(final DatabaseWrapper db,
|
||||
final String participantNumber, final long threadId, final boolean senderBlocked) {
|
||||
final ArrayList<ParticipantData> participants =
|
||||
new ArrayList<ParticipantData>();
|
||||
participants.add(ParticipantData.getFromRawPhoneBySystemLocale(participantNumber));
|
||||
|
||||
final String conversationId = BugleDatabaseOperations.getOrCreateConversation(db, threadId,
|
||||
senderBlocked, participants, false, false, null);
|
||||
assertNotNull("No conversation", conversationId);
|
||||
return conversationId;
|
||||
}
|
||||
|
||||
public void testReadDraft() {
|
||||
final Object data = "data";
|
||||
final String draftMessage = "draftMessage";
|
||||
final long threadId = 1234567;
|
||||
final boolean senderBlocked = false;
|
||||
final String participantNumber = "5552345678";
|
||||
|
||||
final DatabaseWrapper db = DataModel.get().getDatabase();
|
||||
|
||||
final String conversationId = getOrCreateConversation(db, participantNumber, threadId,
|
||||
senderBlocked);
|
||||
final String selfId = getOrCreateSelfId(db);
|
||||
|
||||
// Should clear/stub DB
|
||||
final ArrayList<StubActionServiceCallLog> calls = mService.getCalls();
|
||||
|
||||
final MessageData message = MessageData.createDraftSmsMessage(conversationId, selfId,
|
||||
draftMessage);
|
||||
|
||||
BugleDatabaseOperations.updateDraftMessageData(db, conversationId, message,
|
||||
BugleDatabaseOperations.UPDATE_MODE_ADD_DRAFT);
|
||||
|
||||
final ActionMonitor monitor =
|
||||
ReadDraftDataAction.readDraftData(conversationId, null, data, mockListener);
|
||||
|
||||
assertEquals("Unexpected number of calls to service", 1, calls.size());
|
||||
assertTrue("Action not of type ReadDraftMessageAction",
|
||||
calls.get(0).action instanceof ReadDraftDataAction);
|
||||
|
||||
final Action read = calls.get(0).action;
|
||||
|
||||
final Object result = read.executeAction();
|
||||
|
||||
assertTrue(result instanceof ReadDraftDataAction.DraftData);
|
||||
final ReadDraftDataAction.DraftData draft = (ReadDraftDataAction.DraftData) result;
|
||||
|
||||
assertEquals("Draft message text differs", draftMessage, draft.message.getMessageText());
|
||||
assertEquals("Draft self differs", selfId, draft.message.getSelfId());
|
||||
assertEquals("Draft conversation differs", conversationId,
|
||||
draft.conversation.getConversationId());
|
||||
}
|
||||
|
||||
public void testReadDraftForNewConversation() {
|
||||
final Object data = "data";
|
||||
long threadId = 1234567;
|
||||
final boolean senderBlocked = false;
|
||||
long phoneNumber = 5557654567L;
|
||||
final String notConversationId = "ThisIsNotValidConversationId";
|
||||
|
||||
final DatabaseWrapper db = DataModel.get().getDatabase();
|
||||
final String selfId = getOrCreateSelfId(db);
|
||||
|
||||
// Unless set a new conversation should have a null draft message
|
||||
final MessageData blank = BugleDatabaseOperations.readDraftMessageData(db,
|
||||
notConversationId, selfId);
|
||||
assertNull(blank);
|
||||
|
||||
String conversationId = null;
|
||||
do {
|
||||
conversationId = BugleDatabaseOperations.getExistingConversation(db,
|
||||
threadId, senderBlocked);
|
||||
threadId++;
|
||||
phoneNumber++;
|
||||
}
|
||||
while(!TextUtils.isEmpty(conversationId));
|
||||
|
||||
final ArrayList<ParticipantData> participants =
|
||||
new ArrayList<ParticipantData>();
|
||||
participants.add(ParticipantData.getFromRawPhoneBySystemLocale(Long.toString(phoneNumber)));
|
||||
|
||||
conversationId = BugleDatabaseOperations.getOrCreateConversation(db, threadId,
|
||||
senderBlocked, participants, false, false, null);
|
||||
assertNotNull("No conversation", conversationId);
|
||||
|
||||
final MessageData actual = BugleDatabaseOperations.readDraftMessageData(db, conversationId,
|
||||
selfId);
|
||||
assertNull(actual);
|
||||
|
||||
// Should clear/stub DB
|
||||
final ArrayList<StubActionServiceCallLog> calls = mService.getCalls();
|
||||
|
||||
final ActionMonitor monitor =
|
||||
ReadDraftDataAction.readDraftData(conversationId, null, data, mockListener);
|
||||
|
||||
assertEquals("Unexpected number of calls to service", 1, calls.size());
|
||||
assertTrue("Action not of type ReadDraftMessageAction",
|
||||
calls.get(0).action instanceof ReadDraftDataAction);
|
||||
|
||||
final Action read = calls.get(0).action;
|
||||
|
||||
final Object result = read.executeAction();
|
||||
|
||||
assertTrue(result instanceof ReadDraftDataAction.DraftData);
|
||||
final ReadDraftDataAction.DraftData draft = (ReadDraftDataAction.DraftData) result;
|
||||
|
||||
assertEquals("Draft message text differs", "", draft.message.getMessageText());
|
||||
assertEquals("Draft self differs", selfId, draft.message.getSelfId());
|
||||
assertEquals("Draft conversation differs", conversationId,
|
||||
draft.conversation.getConversationId());
|
||||
}
|
||||
|
||||
public void testWriteAndReadDraft() {
|
||||
final Object data = "data";
|
||||
final String draftMessage = "draftMessage";
|
||||
|
||||
final DatabaseWrapper db = DataModel.get().getDatabase();
|
||||
final Cursor conversations = db.query(DatabaseHelper.CONVERSATIONS_TABLE,
|
||||
new String[] { ConversationColumns._ID, ConversationColumns.CURRENT_SELF_ID }, null,
|
||||
null, null /* groupBy */, null /* having */, null /* orderBy */);
|
||||
|
||||
if (conversations.moveToFirst()) {
|
||||
final String conversationId = conversations.getString(0);
|
||||
final String selfId = getOrCreateSelfId(db);
|
||||
|
||||
// Should clear/stub DB
|
||||
final ArrayList<StubActionServiceCallLog> calls = mService.getCalls();
|
||||
|
||||
final MessageData message = MessageData.createDraftSmsMessage(conversationId, selfId,
|
||||
draftMessage);
|
||||
|
||||
WriteDraftMessageAction.writeDraftMessage(conversationId, message);
|
||||
|
||||
assertEquals("Failed to start service once for action", calls.size(), 1);
|
||||
assertTrue("Action not SaveDraftMessageAction",
|
||||
calls.get(0).action instanceof WriteDraftMessageAction);
|
||||
|
||||
final Action save = calls.get(0).action;
|
||||
|
||||
Object result = save.executeAction();
|
||||
|
||||
assertTrue("Expect row number string as result", result instanceof String);
|
||||
|
||||
// Should check DB
|
||||
|
||||
final ActionMonitor monitor =
|
||||
ReadDraftDataAction.readDraftData(conversationId, null, data,
|
||||
mockListener);
|
||||
|
||||
assertEquals("Expect two calls queued", 2, calls.size());
|
||||
assertTrue("Expect action", calls.get(1).action instanceof ReadDraftDataAction);
|
||||
|
||||
final Action read = calls.get(1).action;
|
||||
|
||||
result = read.executeAction();
|
||||
|
||||
assertTrue(result instanceof ReadDraftDataAction.DraftData);
|
||||
final ReadDraftDataAction.DraftData draft = (ReadDraftDataAction.DraftData) result;
|
||||
|
||||
assertEquals("Draft message text differs", draftMessage, draft.message.getMessageText());
|
||||
// The conversation's self id is used as the draft's self id.
|
||||
assertEquals("Draft self differs", conversations.getString(1),
|
||||
draft.message.getSelfId());
|
||||
assertEquals("Draft conversation differs", conversationId,
|
||||
draft.conversation.getConversationId());
|
||||
} else {
|
||||
fail("No conversations in database");
|
||||
}
|
||||
}
|
||||
|
||||
public void testUpdateDraft() {
|
||||
final String initialMessage = "initialMessage";
|
||||
final String draftMessage = "draftMessage";
|
||||
final long threadId = 1234567;
|
||||
final boolean senderBlocked = false;
|
||||
final String participantNumber = "5553456789";
|
||||
|
||||
final DatabaseWrapper db = DataModel.get().getDatabase();
|
||||
|
||||
final String conversationId = getOrCreateConversation(db, participantNumber, threadId,
|
||||
senderBlocked);
|
||||
final String selfId = getOrCreateSelfId(db);
|
||||
|
||||
final ArrayList<StubActionServiceCallLog> calls = mService.getCalls();
|
||||
|
||||
// Insert initial message
|
||||
MessageData initial = MessageData.createDraftSmsMessage(conversationId, selfId,
|
||||
initialMessage);
|
||||
|
||||
BugleDatabaseOperations.updateDraftMessageData(db, conversationId, initial,
|
||||
BugleDatabaseOperations.UPDATE_MODE_ADD_DRAFT);
|
||||
|
||||
initial = BugleDatabaseOperations.readDraftMessageData(db,
|
||||
conversationId, selfId);
|
||||
assertEquals("Initial text mismatch", initialMessage, initial.getMessageText());
|
||||
|
||||
// Now update the draft
|
||||
final MessageData message = MessageData.createDraftSmsMessage(conversationId, selfId,
|
||||
draftMessage);
|
||||
WriteDraftMessageAction.writeDraftMessage(conversationId, message);
|
||||
|
||||
assertEquals("Failed to start service once for action", calls.size(), 1);
|
||||
assertTrue("Action not SaveDraftMessageAction",
|
||||
calls.get(0).action instanceof WriteDraftMessageAction);
|
||||
|
||||
final Action save = calls.get(0).action;
|
||||
|
||||
final Object result = save.executeAction();
|
||||
|
||||
assertTrue("Expect row number string as result", result instanceof String);
|
||||
|
||||
// Check DB
|
||||
final MessageData actual = BugleDatabaseOperations.readDraftMessageData(db,
|
||||
conversationId, selfId);
|
||||
assertNotNull("Database missing draft", actual);
|
||||
assertEquals("Draft text mismatch", draftMessage, actual.getMessageText());
|
||||
assertNull("Draft messageId should be null", actual.getMessageId());
|
||||
}
|
||||
|
||||
public void testBugleDatabaseDraftOperations() {
|
||||
final String initialMessage = "initialMessage";
|
||||
final String draftMessage = "draftMessage";
|
||||
final long threadId = 1234599;
|
||||
final boolean senderBlocked = false;
|
||||
final String participantNumber = "5553456798";
|
||||
final String subject = "subject here";
|
||||
|
||||
final DatabaseWrapper db = DataModel.get().getDatabase();
|
||||
|
||||
final String conversationId = getOrCreateConversation(db, participantNumber, threadId,
|
||||
senderBlocked);
|
||||
final String selfId = getOrCreateSelfId(db);
|
||||
|
||||
final String text = "This is some text";
|
||||
final Uri mOutputUri = MediaScratchFileProvider.buildMediaScratchSpaceUri("txt");
|
||||
OutputStream outputStream = null;
|
||||
try {
|
||||
outputStream = mContext.getContentResolver().openOutputStream(mOutputUri);
|
||||
outputStream.write(text.getBytes());
|
||||
} catch (final FileNotFoundException e) {
|
||||
fail("Cannot open output file");
|
||||
} catch (final IOException e) {
|
||||
fail("Cannot write output file");
|
||||
}
|
||||
|
||||
final MessageData initial =
|
||||
MessageData.createDraftMmsMessage(conversationId, selfId, initialMessage, subject);
|
||||
initial.addPart(MessagePartData.createMediaMessagePart(ContentType.MULTIPART_MIXED,
|
||||
mOutputUri, 0, 0));
|
||||
|
||||
final String initialMessageId = BugleDatabaseOperations.updateDraftMessageData(db,
|
||||
conversationId, initial, BugleDatabaseOperations.UPDATE_MODE_ADD_DRAFT);
|
||||
assertNotNull(initialMessageId);
|
||||
|
||||
final MessageData initialDraft = BugleDatabaseOperations.readMessage(db, initialMessageId);
|
||||
assertNotNull(initialDraft);
|
||||
int cnt = 0;
|
||||
for(final MessagePartData part : initialDraft.getParts()) {
|
||||
if (part.isAttachment()) {
|
||||
assertEquals(part.getContentUri(), mOutputUri);
|
||||
} else {
|
||||
assertEquals(part.getText(), initialMessage);
|
||||
}
|
||||
cnt++;
|
||||
}
|
||||
assertEquals("Wrong number of parts", 2, cnt);
|
||||
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
inputStream = mContext.getContentResolver().openInputStream(mOutputUri);
|
||||
final byte[] buffer = new byte[256];
|
||||
final int read = inputStream.read(buffer);
|
||||
assertEquals(read, text.getBytes().length);
|
||||
} catch (final FileNotFoundException e) {
|
||||
fail("Cannot open input file");
|
||||
} catch (final IOException e) {
|
||||
fail("Cannot read input file");
|
||||
}
|
||||
|
||||
final String moreText = "This is some more text";
|
||||
final Uri mAnotherUri = MediaScratchFileProvider.buildMediaScratchSpaceUri("txt");
|
||||
outputStream = null;
|
||||
try {
|
||||
outputStream = mContext.getContentResolver().openOutputStream(mAnotherUri);
|
||||
outputStream.write(moreText.getBytes());
|
||||
} catch (final FileNotFoundException e) {
|
||||
fail("Cannot open output file");
|
||||
} catch (final IOException e) {
|
||||
fail("Cannot write output file");
|
||||
}
|
||||
|
||||
final MessageData another =
|
||||
MessageData.createDraftMmsMessage(conversationId, selfId, draftMessage, subject);
|
||||
another.addPart(MessagePartData.createMediaMessagePart(ContentType.MMS_MULTIPART_MIXED,
|
||||
mAnotherUri, 0, 0));
|
||||
|
||||
final String anotherMessageId = BugleDatabaseOperations.updateDraftMessageData(db,
|
||||
conversationId, another, BugleDatabaseOperations.UPDATE_MODE_ADD_DRAFT);
|
||||
assertNotNull(anotherMessageId);
|
||||
|
||||
final MessageData anotherDraft = BugleDatabaseOperations.readMessage(db, anotherMessageId);
|
||||
assertNotNull(anotherDraft);
|
||||
cnt = 0;
|
||||
for(final MessagePartData part : anotherDraft.getParts()) {
|
||||
if (part.isAttachment()) {
|
||||
assertEquals(part.getContentUri(), mAnotherUri);
|
||||
} else {
|
||||
assertEquals(part.getText(), draftMessage);
|
||||
}
|
||||
cnt++;
|
||||
}
|
||||
assertEquals("Wrong number of parts", 2, cnt);
|
||||
|
||||
inputStream = null;
|
||||
try {
|
||||
inputStream = mContext.getContentResolver().openInputStream(mOutputUri);
|
||||
assertNull("Original draft content should have been deleted", inputStream);
|
||||
} catch (final FileNotFoundException e) {
|
||||
}
|
||||
inputStream = null;
|
||||
try {
|
||||
inputStream = mContext.getContentResolver().openInputStream(mAnotherUri);
|
||||
final byte[] buffer = new byte[256];
|
||||
final int read = inputStream.read(buffer);
|
||||
assertEquals(read, moreText.getBytes().length);
|
||||
} catch (final FileNotFoundException e) {
|
||||
fail("Cannot open input file");
|
||||
} catch (final IOException e) {
|
||||
fail("Cannot read input file");
|
||||
}
|
||||
|
||||
final MessageData last = null;
|
||||
final String lastPartId = BugleDatabaseOperations.updateDraftMessageData(db,
|
||||
conversationId, last, BugleDatabaseOperations.UPDATE_MODE_ADD_DRAFT);
|
||||
assertNull(lastPartId);
|
||||
|
||||
inputStream = null;
|
||||
try {
|
||||
inputStream = mContext.getContentResolver().openInputStream(mAnotherUri);
|
||||
assertNull("Original draft content should have been deleted", inputStream);
|
||||
} catch (final FileNotFoundException e) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private StubActionService mService;
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
final FakeContext context = new FakeContext(getTestContext());
|
||||
|
||||
final ContentProvider bugleProvider = new MessagingContentProvider();
|
||||
final ProviderInfo bugleProviderInfo = new ProviderInfo();
|
||||
bugleProviderInfo.authority = MessagingContentProvider.AUTHORITY;
|
||||
bugleProvider.attachInfo(mContext, bugleProviderInfo);
|
||||
context.addContentProvider(MessagingContentProvider.AUTHORITY, bugleProvider);
|
||||
final ContentProvider mediaProvider = new MediaScratchFileProvider();
|
||||
final ProviderInfo mediaProviderInfo = new ProviderInfo();
|
||||
mediaProviderInfo.authority = MediaScratchFileProvider.AUTHORITY;
|
||||
mediaProvider.attachInfo(mContext, mediaProviderInfo);
|
||||
context.addContentProvider(MediaScratchFileProvider.AUTHORITY, mediaProvider);
|
||||
|
||||
mService = new StubActionService();
|
||||
final FakeDataModel fakeDataModel = new FakeDataModel(context)
|
||||
.withActionService(mService)
|
||||
.withConnectivityUtil(new StubConnectivityUtil(context));
|
||||
FakeFactory.registerWithFakeContext(getTestContext(), context)
|
||||
.withDataModel(fakeDataModel);
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user