| /* |
| * 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); |
| } |
| } |
| } |