1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.messaging.datamodel.action; 18 19 import android.content.Intent; 20 import android.os.Bundle; 21 import android.os.Parcel; 22 import android.os.Parcelable; 23 import android.test.suitebuilder.annotation.MediumTest; 24 import android.util.Log; 25 26 import com.android.messaging.BugleTestCase; 27 import com.android.messaging.Factory; 28 import com.android.messaging.FakeContext; 29 import com.android.messaging.FakeContext.FakeContextHost; 30 import com.android.messaging.FakeFactory; 31 import com.android.messaging.datamodel.BugleServiceTestCase; 32 import com.android.messaging.datamodel.DataModel; 33 import com.android.messaging.datamodel.FakeDataModel; 34 import com.android.messaging.datamodel.action.ActionMonitor.ActionCompletedListener; 35 import com.android.messaging.datamodel.action.ActionMonitor.ActionExecutedListener; 36 import com.android.messaging.datamodel.action.ActionTestHelpers.ResultTracker; 37 import com.android.messaging.datamodel.action.ActionTestHelpers.StubBackgroundWorker; 38 import com.android.messaging.datamodel.action.ActionTestHelpers.StubLoader; 39 40 import java.util.ArrayList; 41 42 @MediumTest 43 public class ActionServiceSystemTest extends BugleServiceTestCase<ActionServiceImpl> 44 implements ActionCompletedListener, ActionExecutedListener, FakeContextHost { 45 private static final String TAG = "ActionServiceSystemTest"; 46 47 static { 48 // Set flag during loading of test cases to prevent application initialization starting BugleTestCase.setTestsRunning()49 BugleTestCase.setTestsRunning(); 50 } 51 52 @Override onActionSucceeded(final ActionMonitor monitor, final Action action, final Object data, final Object result)53 public void onActionSucceeded(final ActionMonitor monitor, 54 final Action action, final Object data, final Object result) { 55 final TestChatAction test = (TestChatAction) action; 56 assertEquals("Expect correct action parameter", parameter, test.parameter); 57 final ResultTracker tracker = (ResultTracker) data; 58 tracker.completionResult = result; 59 synchronized(tracker) { 60 tracker.notifyAll(); 61 } 62 } 63 64 @Override onActionFailed(final ActionMonitor monitor, final Action action, final Object data, final Object result)65 public void onActionFailed(final ActionMonitor monitor, final Action action, 66 final Object data, final Object result) { 67 final TestChatAction test = (TestChatAction) action; 68 assertEquals("Expect correct action parameter", parameter, test.parameter); 69 final ResultTracker tracker = (ResultTracker) data; 70 tracker.completionResult = result; 71 synchronized(tracker) { 72 tracker.notifyAll(); 73 } 74 } 75 76 @Override onActionExecuted(final ActionMonitor monitor, final Action action, final Object data, final Object result)77 public void onActionExecuted(final ActionMonitor monitor, final Action action, 78 final Object data, final Object result) { 79 final TestChatAction test = (TestChatAction) action; 80 assertEquals("Expect correct action parameter", parameter, test.parameter); 81 final ResultTracker tracker = (ResultTracker) data; 82 tracker.executionResult = result; 83 } 84 ActionServiceSystemTest()85 public ActionServiceSystemTest() { 86 super(ActionServiceImpl.class); 87 } 88 testChatActionSucceeds()89 public void testChatActionSucceeds() { 90 final ResultTracker tracker = new ResultTracker(); 91 92 final ActionService service = DataModel.get().getActionService(); 93 final TestChatActionMonitor monitor = new TestChatActionMonitor(null, tracker, this, this); 94 final TestChatAction initial = new TestChatAction(monitor.getActionKey(), parameter); 95 96 assertNull("Expect completion result to start null", tracker.completionResult); 97 assertNull("Expect execution result to start null", tracker.executionResult); 98 99 final Parcel parcel = Parcel.obtain(); 100 parcel.writeParcelable(initial, 0); 101 parcel.setDataPosition(0); 102 final TestChatAction action = parcel.readParcelable(mContext.getClassLoader()); 103 104 synchronized(mWorker) { 105 try { 106 action.start(monitor); 107 // Wait for callback across threads 108 mWorker.wait(2000); 109 } catch (final InterruptedException e) { 110 assertTrue("Interrupted waiting for execution", false); 111 } 112 } 113 114 assertEquals("Expect to see 1 server request queued", 1, 115 mWorker.getRequestsMade().size()); 116 final Action request = mWorker.getRequestsMade().get(0); 117 assertTrue("Expect Test type", request instanceof TestChatAction); 118 119 final Bundle response = new Bundle(); 120 response.putString(TestChatAction.RESPONSE_TEST, processResponseResult); 121 synchronized(tracker) { 122 try { 123 request.markBackgroundWorkStarting(); 124 request.markBackgroundWorkQueued(); 125 126 request.markBackgroundWorkStarting(); 127 request.markBackgroundCompletionQueued(); 128 service.handleResponseFromBackgroundWorker(request, response); 129 // Wait for callback across threads 130 tracker.wait(2000); 131 } catch (final InterruptedException e) { 132 assertTrue("Interrupted waiting for response processing", false); 133 } 134 } 135 136 // TODO 137 //assertEquals("Expect execution result set", executeActionResult, tracker.executionResult); 138 assertEquals("Expect completion result set", processResponseResult, 139 tracker.completionResult); 140 } 141 testChatActionFails()142 public void testChatActionFails() { 143 final ResultTracker tracker = new ResultTracker(); 144 145 final ActionService service = DataModel.get().getActionService(); 146 final TestChatActionMonitor monitor = new TestChatActionMonitor(null, tracker, this, this); 147 final TestChatAction action = new TestChatAction(monitor.getActionKey(), parameter); 148 149 assertNull("Expect completion result to start null", tracker.completionResult); 150 assertNull("Expect execution result to start null", tracker.executionResult); 151 152 synchronized(mWorker) { 153 try { 154 action.start(monitor); 155 // Wait for callback across threads 156 mWorker.wait(2000); 157 } catch (final InterruptedException e) { 158 assertTrue("Interrupted waiting for requests", false); 159 } 160 } 161 162 assertEquals("Expect to see 1 server request queued", 1, 163 mWorker.getRequestsMade().size()); 164 final Action request = mWorker.getRequestsMade().get(0); 165 assertTrue("Expect Test type", request instanceof TestChatAction); 166 167 synchronized(tracker) { 168 try { 169 request.markBackgroundWorkStarting(); 170 request.markBackgroundWorkQueued(); 171 172 request.markBackgroundWorkStarting(); 173 request.markBackgroundCompletionQueued(); 174 service.handleFailureFromBackgroundWorker(request, new Exception("It went wrong")); 175 // Wait for callback across threads 176 tracker.wait(2000); 177 } catch (final InterruptedException e) { 178 assertTrue("Interrupted waiting for response processing", false); 179 } 180 } 181 182 // TODO 183 //assertEquals("Expect execution result set", executeActionResult, tracker.executionResult); 184 assertEquals("Expect completion result set", processFailureResult, 185 tracker.completionResult); 186 } 187 testChatActionNoMonitor()188 public void testChatActionNoMonitor() { 189 final ActionService service = DataModel.get().getActionService(); 190 final TestChatAction action = 191 new TestChatAction(Action.generateUniqueActionKey(null), parameter); 192 193 synchronized(mWorker) { 194 try { 195 action.start(); 196 // Wait for callback across threads 197 mWorker.wait(2000); 198 } catch (final InterruptedException e) { 199 assertTrue("Interrupted waiting for execution", false); 200 } 201 } 202 203 assertEquals("Expect to see 1 server request queued", 1, 204 mWorker.getRequestsMade().size()); 205 Action request = mWorker.getRequestsMade().get(0); 206 assertTrue("Expect Test type", request instanceof TestChatAction); 207 208 final Bundle response = new Bundle(); 209 response.putString(TestChatAction.RESPONSE_TEST, processResponseResult); 210 synchronized(mWorker) { 211 try { 212 service.handleResponseFromBackgroundWorker(request, response); 213 // Wait for callback across threads 214 mWorker.wait(2000); 215 } catch (final InterruptedException e) { 216 assertTrue("Interrupted waiting for response processing", false); 217 } 218 } 219 220 assertEquals("Expect to see second server request queued", 221 2, mWorker.getRequestsMade().size()); 222 request = mWorker.getRequestsMade().get(1); 223 assertTrue("Expect other type", 224 request instanceof TestChatActionOther); 225 } 226 testChatActionUnregisterListener()227 public void testChatActionUnregisterListener() { 228 final ResultTracker tracker = new ResultTracker(); 229 230 final ActionService service = DataModel.get().getActionService(); 231 final TestChatActionMonitor monitor = new TestChatActionMonitor(null, tracker, this, this); 232 final TestChatAction action = new TestChatAction(monitor.getActionKey(), parameter); 233 234 assertNull("Expect completion result to start null", tracker.completionResult); 235 assertNull("Expect execution result to start null", tracker.executionResult); 236 237 synchronized(mWorker) { 238 try { 239 action.start(monitor); 240 // Wait for callback across threads 241 mWorker.wait(2000); 242 } catch (final InterruptedException e) { 243 assertTrue("Interrupted waiting for execution", false); 244 } 245 } 246 247 assertEquals("Expect to see 1 server request queued", 1, 248 mWorker.getRequestsMade().size()); 249 final Action request = mWorker.getRequestsMade().get(0); 250 assertTrue("Expect Test type", request instanceof TestChatAction); 251 252 monitor.unregister(); 253 254 final Bundle response = new Bundle(); 255 synchronized(mWorker) { 256 try { 257 request.markBackgroundWorkStarting(); 258 request.markBackgroundWorkQueued(); 259 260 request.markBackgroundWorkStarting(); 261 request.markBackgroundCompletionQueued(); 262 service.handleResponseFromBackgroundWorker(request, response); 263 // Wait for callback across threads 264 mWorker.wait(2000); 265 } catch (final InterruptedException e) { 266 assertTrue("Interrupted waiting for response processing", false); 267 } 268 } 269 270 //assertEquals("Expect execution result set", executeActionResult, tracker.executionResult); 271 assertEquals("Expect completion never called", null, tracker.completionResult); 272 } 273 274 StubBackgroundWorker mWorker; 275 FakeContext mContext; 276 StubLoader mLoader; 277 278 private static final String parameter = "parameter"; 279 private static final Object executeActionResult = "executeActionResult"; 280 private static final String processResponseResult = "processResponseResult"; 281 private static final Object processFailureResult = "processFailureResult"; 282 283 @Override setUp()284 public void setUp() throws Exception { 285 super.setUp(); 286 Log.d(TAG, "ChatActionTest setUp"); 287 288 mContext = new FakeContext(getContext(), this); 289 mWorker = new StubBackgroundWorker(); 290 FakeFactory.registerWithFakeContext(getContext(), mContext) 291 .withDataModel(new FakeDataModel(mContext) 292 .withBackgroundWorkerForActionService(mWorker) 293 .withActionService(new ActionService())); 294 295 mLoader = new StubLoader(); 296 setContext(Factory.get().getApplicationContext()); 297 } 298 299 @Override getServiceClassName()300 public String getServiceClassName() { 301 return ActionServiceImpl.class.getName(); 302 } 303 304 @Override startServiceForStub(final Intent intent)305 public void startServiceForStub(final Intent intent) { 306 this.startService(intent); 307 } 308 309 @Override onStartCommandForStub(final Intent intent, final int flags, final int startId)310 public void onStartCommandForStub(final Intent intent, final int flags, final int startId) { 311 this.getService().onStartCommand(intent, flags, startId); 312 } 313 314 public static class TestChatAction extends Action implements Parcelable { 315 public static String RESPONSE_TEST = "response_test"; 316 public static String KEY_PARAMETER = "parameter"; 317 TestChatAction(final String key, final String parameter)318 protected TestChatAction(final String key, final String parameter) { 319 super(key); 320 this.actionParameters.putString(KEY_PARAMETER, parameter); 321 // Cache parameter as a member variable 322 this.parameter = parameter; 323 } 324 325 // An example parameter 326 public final String parameter; 327 328 /** 329 * Process the action locally - runs on datamodel service thread 330 */ 331 @Override executeAction()332 protected Object executeAction() { 333 requestBackgroundWork(); 334 return executeActionResult; 335 } 336 337 /** 338 * Process the response from the server - runs on datamodel service thread 339 */ 340 @Override processBackgroundResponse(final Bundle response)341 protected Object processBackgroundResponse(final Bundle response) { 342 requestBackgroundWork(new TestChatActionOther(null, parameter)); 343 return response.get(RESPONSE_TEST); 344 } 345 346 /** 347 * Called in case of failures when sending requests - runs on datamodel service thread 348 */ 349 @Override processBackgroundFailure()350 protected Object processBackgroundFailure() { 351 return processFailureResult; 352 } 353 TestChatAction(final Parcel in)354 private TestChatAction(final Parcel in) { 355 super(in); 356 // Cache parameter as a member variable 357 parameter = actionParameters.getString(KEY_PARAMETER); 358 } 359 360 public static final Parcelable.Creator<TestChatAction> CREATOR 361 = new Parcelable.Creator<TestChatAction>() { 362 @Override 363 public TestChatAction createFromParcel(final Parcel in) { 364 return new TestChatAction(in); 365 } 366 367 @Override 368 public TestChatAction[] newArray(final int size) { 369 return new TestChatAction[size]; 370 } 371 }; 372 373 @Override writeToParcel(final Parcel parcel, final int flags)374 public void writeToParcel(final Parcel parcel, final int flags) { 375 writeActionToParcel(parcel, flags); 376 } 377 } 378 379 public static class TestChatActionOther extends Action implements Parcelable { TestChatActionOther(final String key, final String parameter)380 protected TestChatActionOther(final String key, final String parameter) { 381 super(generateUniqueActionKey(key)); 382 this.parameter = parameter; 383 } 384 385 public final String parameter; 386 TestChatActionOther(final Parcel in)387 private TestChatActionOther(final Parcel in) { 388 super(in); 389 parameter = in.readString(); 390 } 391 392 public static final Parcelable.Creator<TestChatActionOther> CREATOR 393 = new Parcelable.Creator<TestChatActionOther>() { 394 @Override 395 public TestChatActionOther createFromParcel(final Parcel in) { 396 return new TestChatActionOther(in); 397 } 398 399 @Override 400 public TestChatActionOther[] newArray(final int size) { 401 return new TestChatActionOther[size]; 402 } 403 }; 404 405 @Override writeToParcel(final Parcel parcel, final int flags)406 public void writeToParcel(final Parcel parcel, final int flags) { 407 writeActionToParcel(parcel, flags); 408 parcel.writeString(parameter); 409 } 410 } 411 412 /** 413 * An operation that notifies a listener upon completion 414 */ 415 public static class TestChatActionMonitor extends ActionMonitor { 416 /** 417 * Create action state wrapping an BlockUserAction instance 418 * @param account - account in which to block the user 419 * @param baseKey - suggested action key from BlockUserAction 420 * @param data - optional action specific data that is handed back to listener 421 * @param listener - action completed listener 422 */ TestChatActionMonitor(final String baseKey, final Object data, final ActionCompletedListener completed, final ActionExecutedListener executed)423 public TestChatActionMonitor(final String baseKey, final Object data, 424 final ActionCompletedListener completed, final ActionExecutedListener executed) { 425 super(STATE_CREATED, Action.generateUniqueActionKey(baseKey), data); 426 setCompletedListener(completed); 427 setExecutedListener(executed); 428 } 429 } 430 } 431