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