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