blob: 6f66fa94c918aa59be32c8c0131a55afd111033c [file] [log] [blame]
/*
* 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 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);
synchronized(mWorker) {
try {
action.start(monitor);
// Wait for callback across threads
mWorker.wait(2000);
mServiceStarted = true;
} catch (final InterruptedException e) {
assertTrue("Interrupted waiting for execution", false);
}
}
assertTrue("Expect service started", mServiceStarted);
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);
}
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);
}
}
}