1 /*
2  * Copyright (C) 2010 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.tradefed.device;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertFalse;
21 import static org.junit.Assert.assertNotNull;
22 import static org.junit.Assert.assertNull;
23 import static org.junit.Assert.assertTrue;
24 import static org.junit.Assert.fail;
25 import static org.mockito.Mockito.doAnswer;
26 import static org.mockito.Mockito.doNothing;
27 import static org.mockito.Mockito.doThrow;
28 import static org.mockito.Mockito.mock;
29 import static org.mockito.Mockito.times;
30 import static org.mockito.Mockito.verify;
31 import static org.mockito.Mockito.when;
32 
33 import com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener;
34 import com.android.ddmlib.IDevice;
35 import com.android.ddmlib.IDevice.DeviceState;
36 import com.android.tradefed.command.remote.DeviceDescriptor;
37 import com.android.tradefed.config.IGlobalConfiguration;
38 import com.android.tradefed.config.OptionSetter;
39 import com.android.tradefed.device.IManagedTestDevice.DeviceEventResponse;
40 import com.android.tradefed.host.HostOptions;
41 import com.android.tradefed.host.IHostOptions;
42 import com.android.tradefed.log.ILogRegistry.EventType;
43 import com.android.tradefed.util.ArrayUtil;
44 import com.android.tradefed.util.CommandResult;
45 import com.android.tradefed.util.CommandStatus;
46 import com.android.tradefed.util.FileUtil;
47 import com.android.tradefed.util.IRunUtil;
48 import com.android.tradefed.util.ZipUtil;
49 
50 import org.junit.Before;
51 import org.junit.Test;
52 import org.junit.runner.RunWith;
53 import org.junit.runners.JUnit4;
54 import org.mockito.ArgumentCaptor;
55 import org.mockito.Mock;
56 import org.mockito.Mockito;
57 import org.mockito.MockitoAnnotations;
58 
59 import java.io.ByteArrayOutputStream;
60 import java.io.File;
61 import java.io.InputStream;
62 import java.io.OutputStream;
63 import java.io.PrintWriter;
64 import java.util.ArrayList;
65 import java.util.List;
66 import java.util.concurrent.TimeUnit;
67 
68 /** Unit tests for {@link DeviceManager}. */
69 @RunWith(JUnit4.class)
70 public class DeviceManagerTest {
71 
72     private static final String DEVICE_SERIAL = "serial";
73     private static final String MAC_ADDRESS = "FF:FF:FF:FF:FF:FF";
74     private static final String SIM_STATE = "READY";
75     private static final String SIM_OPERATOR = "operator";
76 
77     @Mock IAndroidDebugBridge mMockAdbBridge;
78     @Mock IDevice mMockIDevice;
79     @Mock IDeviceStateMonitor mMockStateMonitor;
80     @Mock IRunUtil mMockRunUtil;
81     @Mock IHostOptions mMockHostOptions;
82     @Mock IManagedTestDevice mMockTestDevice;
83     private IManagedTestDeviceFactory mMockDeviceFactory;
84     @Mock IGlobalConfiguration mMockGlobalConfig;
85     private DeviceSelectionOptions mDeviceSelections;
86 
87     /**
88      * a reference to the DeviceManager's IDeviceChangeListener. Used for triggering device
89      * connection events
90      */
91     private IDeviceChangeListener mDeviceListener;
92 
93     static class MockProcess extends Process {
94         /** {@inheritDoc} */
95         @Override
destroy()96         public void destroy() {
97             // ignore
98         }
99 
100         /** {@inheritDoc} */
101         @Override
exitValue()102         public int exitValue() {
103             return 0;
104         }
105 
106         /** {@inheritDoc} */
107         @Override
getErrorStream()108         public InputStream getErrorStream() {
109             return null;
110         }
111 
112         /** {@inheritDoc} */
113         @Override
getInputStream()114         public InputStream getInputStream() {
115             return null;
116         }
117 
118         /** {@inheritDoc} */
119         @Override
getOutputStream()120         public OutputStream getOutputStream() {
121             return null;
122         }
123 
124         /** {@inheritDoc} */
125         @Override
waitFor()126         public int waitFor() throws InterruptedException {
127             return 0;
128         }
129     }
130 
131     @Before
setUp()132     public void setUp() throws Exception {
133         MockitoAnnotations.initMocks(this);
134 
135         doAnswer(
136                         invocation -> {
137                             Object arg0 = invocation.getArgument(0);
138                             mDeviceListener = (IDeviceChangeListener) arg0;
139                             return null;
140                         })
141                 .when(mMockAdbBridge)
142                 .addDeviceChangeListener((IDeviceChangeListener) Mockito.any());
143 
144         mMockDeviceFactory =
145                 new ManagedTestDeviceFactory(false, null, null) {
146                     @Override
147                     public IManagedTestDevice createDevice(IDevice idevice) {
148                         mMockTestDevice.setIDevice(idevice);
149                         return mMockTestDevice;
150                     }
151 
152                     @Override
153                     protected CollectingOutputReceiver createOutputReceiver() {
154                         return new CollectingOutputReceiver() {
155                             @Override
156                             public String getOutput() {
157                                 return "/system/bin/pm";
158                             }
159                         };
160                     }
161 
162                     @Override
163                     public void setFastbootEnabled(boolean enable) {
164                         // ignore
165                     }
166                 };
167 
168         when(mMockGlobalConfig.getHostOptions()).thenReturn(new HostOptions());
169 
170         when(mMockIDevice.getSerialNumber()).thenReturn(DEVICE_SERIAL);
171         when(mMockStateMonitor.getSerialNumber()).thenReturn(DEVICE_SERIAL);
172 
173         when(mMockIDevice.isEmulator()).thenReturn(Boolean.FALSE);
174         when(mMockTestDevice.getMacAddress()).thenReturn(MAC_ADDRESS);
175         when(mMockTestDevice.getSimState()).thenReturn(SIM_STATE);
176         when(mMockTestDevice.getSimOperator()).thenReturn(SIM_OPERATOR);
177         final ArgumentCaptor<IDevice> capturedIDevice = ArgumentCaptor.forClass(IDevice.class);
178         doNothing().when(mMockTestDevice).setIDevice(capturedIDevice.capture());
179 
180         when(mMockTestDevice.getIDevice())
181                 .thenAnswer(
182                         invocation -> {
183                             return capturedIDevice.getValue();
184                         });
185         when(mMockTestDevice.getSerialNumber())
186                 .thenAnswer(
187                         invocation -> {
188                             return capturedIDevice.getValue().getSerialNumber();
189                         });
190         when(mMockTestDevice.getMonitor()).thenReturn(mMockStateMonitor);
191         when(mMockRunUtil.runTimedCmd(
192                         Mockito.anyLong(), (String) Mockito.any(), (String) Mockito.any()))
193                 .thenReturn(new CommandResult());
194         when(mMockRunUtil.runTimedCmdSilently(
195                         Mockito.anyLong(), (String) Mockito.any(), (String) Mockito.any()))
196                 .thenReturn(new CommandResult());
197         // Avoid any issue related to env. variable.
198         mDeviceSelections =
199                 new DeviceSelectionOptions() {
200                     @Override
201                     public String fetchEnvironmentVariable(String name) {
202                         return null;
203                     }
204                 };
205         when(mMockGlobalConfig.getDeviceRequirements()).thenReturn(mDeviceSelections);
206     }
207 
createDeviceManager( List<IDeviceMonitor> deviceMonitors, IDevice... devices)208     private DeviceManager createDeviceManager(
209             List<IDeviceMonitor> deviceMonitors, IDevice... devices) {
210         DeviceManager mgr = createDeviceManagerNoInit();
211         mgr.init(null, deviceMonitors, mMockDeviceFactory);
212         for (IDevice device : devices) {
213             mDeviceListener.deviceConnected(device);
214         }
215         return mgr;
216     }
217 
createDeviceManagerNoInit()218     private DeviceManager createDeviceManagerNoInit() {
219 
220         DeviceManager mgr =
221                 new DeviceManager() {
222                     @Override
223                     IAndroidDebugBridge createAdbBridge() {
224                         return mMockAdbBridge;
225                     }
226 
227                     @Override
228                     void startFastbootMonitor() {}
229 
230                     @Override
231                     void startDeviceRecoverer() {}
232 
233                     @Override
234                     void logDeviceEvent(EventType event, String serial) {}
235 
236                     @Override
237                     IDeviceStateMonitor createStateMonitor(IDevice device) {
238                         return mMockStateMonitor;
239                     }
240 
241                     @Override
242                     IGlobalConfiguration getGlobalConfig() {
243                         return mMockGlobalConfig;
244                     }
245 
246                     @Override
247                     IRunUtil getRunUtil() {
248                         return mMockRunUtil;
249                     }
250 
251                     @Override
252                     IHostOptions getHostOptions() {
253                         return mMockHostOptions;
254                     }
255                 };
256         mgr.setSynchronousMode(true);
257         mgr.setMaxEmulators(0);
258         mgr.setMaxNullDevices(0);
259         mgr.setMaxGceDevices(0);
260         mgr.setMaxRemoteDevices(0);
261         return mgr;
262     }
263 
264     /**
265      * Test @link DeviceManager#allocateDevice()} when a IDevice is present on DeviceManager
266      * creation.
267      */
268     @Test
testAllocateDevice()269     public void testAllocateDevice() {
270         setCheckAvailableDeviceExpectations();
271         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.ALLOCATE_REQUEST))
272                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Allocated, true));
273 
274         DeviceManager manager = createDeviceManager(null, mMockIDevice);
275         assertNotNull(manager.allocateDevice(mDeviceSelections));
276     }
277 
278     /**
279      * Test {@link DeviceManager#allocateDevice(IDeviceSelection, boolean)} when device is returned.
280      */
281     @Test
testAllocateDevice_match()282     public void testAllocateDevice_match() {
283         mDeviceSelections.addSerial(DEVICE_SERIAL);
284         setCheckAvailableDeviceExpectations();
285         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.EXPLICIT_ALLOCATE_REQUEST))
286                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Allocated, true));
287 
288         DeviceManager manager = createDeviceManager(null, mMockIDevice);
289         assertEquals(mMockTestDevice, manager.allocateDevice(mDeviceSelections, false));
290     }
291 
292     /**
293      * Test that when allocating a fake device we create a placeholder then delete it at the end.
294      */
295     @Test
testAllocateDevice_match_temporary()296     public void testAllocateDevice_match_temporary() {
297         mDeviceSelections.setNullDeviceRequested(true);
298         mDeviceSelections.addSerial(DEVICE_SERIAL);
299         // Force create a device
300         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.FORCE_AVAILABLE))
301                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Available, true));
302         // Device get allocated
303         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.EXPLICIT_ALLOCATE_REQUEST))
304                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Allocated, true));
305 
306         mMockTestDevice.stopLogcat();
307 
308         // De-allocate
309         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.FREE_UNKNOWN))
310                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Unknown, true));
311 
312         DeviceManager manager = createDeviceManager(null);
313         assertEquals(mMockTestDevice, manager.allocateDevice(mDeviceSelections, true));
314         String serial = mMockTestDevice.getSerialNumber();
315         assertTrue(serial.startsWith("null-device-temp-"));
316 
317         // Release device
318         manager.freeDevice(mMockTestDevice, FreeDeviceState.AVAILABLE);
319         // Check that temp device was deleted.
320         DeviceSelectionOptions validation = new DeviceSelectionOptions();
321         validation.setNullDeviceRequested(true);
322         validation.addSerial(serial);
323         // If we request the particular null-device again it doesn't exists.
324         assertNull(manager.allocateDevice(validation, false));
325     }
326 
327     /**
328      * Test {@link DeviceManager#allocateDevice(IDeviceSelection, boolean)} when stub emulator is
329      * requested.
330      */
331     @Test
testAllocateDevice_stubEmulator()332     public void testAllocateDevice_stubEmulator() {
333         mDeviceSelections.setStubEmulatorRequested(true);
334         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.FORCE_AVAILABLE))
335                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Available, true));
336         when(mMockIDevice.isEmulator()).thenReturn(Boolean.TRUE);
337         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.ALLOCATE_REQUEST))
338                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Allocated, true));
339 
340         DeviceManager mgr = createDeviceManagerNoInit();
341         mgr.setMaxEmulators(1);
342         mgr.init(null, null, mMockDeviceFactory);
343         assertNotNull(mgr.allocateDevice(mDeviceSelections, false));
344     }
345 
346     /** Test that when a zipped fastboot file is provided we unpack it and use it. */
347     @Test
testUnpackZippedFastboot()348     public void testUnpackZippedFastboot() throws Exception {
349         File tmpDir = FileUtil.createTempDir("fake-fastbootdir");
350         File fastboot = new File(tmpDir, "fastboot");
351         FileUtil.writeToFile("TEST", fastboot);
352         File zipDir = ZipUtil.createZip(tmpDir);
353 
354         DeviceManager mgr = createDeviceManagerNoInit();
355         try {
356             OptionSetter setter = new OptionSetter(mgr);
357             setter.setOptionValue("fastboot-path", zipDir.getAbsolutePath());
358             mgr.init(null, null, mMockDeviceFactory);
359             assertTrue(mgr.getFastbootPath().contains("fastboot"));
360             assertEquals("TEST", FileUtil.readStringFromFile(new File(mgr.getFastbootPath())));
361         } finally {
362             FileUtil.recursiveDelete(tmpDir);
363             FileUtil.deleteFile(zipDir);
364             mgr.terminate();
365         }
366     }
367 
368     /** Test freeing an emulator */
369     @Test
testFreeDevice_emulator()370     public void testFreeDevice_emulator() throws DeviceNotAvailableException {
371         mDeviceSelections.setStubEmulatorRequested(true);
372         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.FORCE_AVAILABLE))
373                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Available, true));
374         when(mMockIDevice.isEmulator()).thenReturn(Boolean.TRUE);
375         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.ALLOCATE_REQUEST))
376                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Allocated, true));
377 
378         when(mMockTestDevice.executeAdbCommand("emu", "kill")).thenReturn("");
379         when(mMockTestDevice.getEmulatorProcess()).thenReturn(new MockProcess());
380         when(mMockTestDevice.waitForDeviceNotAvailable(Mockito.anyLong())).thenReturn(Boolean.TRUE);
381         when(mMockTestDevice.waitForDeviceNotAvailable(Mockito.anyLong())).thenReturn(Boolean.TRUE);
382         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.FREE_AVAILABLE))
383                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Available, true));
384         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.ALLOCATE_REQUEST))
385                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Allocated, true));
386 
387         DeviceManager manager = createDeviceManagerNoInit();
388         manager.setMaxEmulators(1);
389         manager.init(null, null, mMockDeviceFactory);
390         IManagedTestDevice emulator =
391                 (IManagedTestDevice) manager.allocateDevice(mDeviceSelections, false);
392         assertNotNull(emulator);
393         // a freed 'unavailable' emulator should be returned to the available
394         // queue.
395         manager.freeDevice(emulator, FreeDeviceState.UNAVAILABLE);
396         // ensure device can be allocated again
397         assertNotNull(manager.allocateDevice(mDeviceSelections, false));
398 
399         verify(mMockTestDevice).stopLogcat();
400         verify(mMockTestDevice).stopEmulatorOutput();
401     }
402 
403     /**
404      * Test {@link DeviceManager#allocateDevice(IDeviceSelection, boolean)} when a null device is
405      * requested.
406      */
407     @Test
testAllocateDevice_nullDevice()408     public void testAllocateDevice_nullDevice() {
409         mDeviceSelections.setNullDeviceRequested(true);
410         when(mMockIDevice.isEmulator()).thenReturn(Boolean.FALSE);
411         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.FORCE_AVAILABLE))
412                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Available, true));
413         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.ALLOCATE_REQUEST))
414                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Allocated, true));
415 
416         DeviceManager mgr = createDeviceManagerNoInit();
417         mgr.setMaxNullDevices(1);
418         mgr.init(null, null, mMockDeviceFactory);
419         ITestDevice device = mgr.allocateDevice(mDeviceSelections, false);
420         assertNotNull(device);
421         assertTrue(device.getIDevice() instanceof NullDevice);
422     }
423 
424     /** Test {@link DeviceManager#forceAllocateDevice(String)} when device is unknown */
425     @Test
testForceAllocateDevice()426     public void testForceAllocateDevice() {
427 
428         DeviceManager manager = createDeviceManager(null);
429         assertNull(manager.forceAllocateDevice("unknownserial"));
430     }
431 
432     /** Test {@link DeviceManager#forceAllocateDevice(String)} when device is available */
433     @Test
testForceAllocateDevice_available()434     public void testForceAllocateDevice_available() {
435         setCheckAvailableDeviceExpectations();
436         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.FORCE_ALLOCATE_REQUEST))
437                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Allocated, true));
438 
439         DeviceManager manager = createDeviceManager(null, mMockIDevice);
440         assertNotNull(manager.forceAllocateDevice(DEVICE_SERIAL));
441     }
442 
443     /** Test {@link DeviceManager#forceAllocateDevice(String)} when device is already allocated */
444     @Test
testForceAllocateDevice_alreadyAllocated()445     public void testForceAllocateDevice_alreadyAllocated() {
446         setCheckAvailableDeviceExpectations();
447         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.ALLOCATE_REQUEST))
448                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Allocated, true));
449         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.FORCE_ALLOCATE_REQUEST))
450                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Allocated, false));
451 
452         DeviceManager manager = createDeviceManager(null, mMockIDevice);
453         assertNotNull(manager.allocateDevice(mDeviceSelections));
454         assertNull(manager.forceAllocateDevice(DEVICE_SERIAL));
455     }
456 
457     /** Test method for {@link DeviceManager#freeDevice(ITestDevice, FreeDeviceState)}. */
458     @Test
testFreeDevice()459     public void testFreeDevice() {
460         setCheckAvailableDeviceExpectations();
461         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.ALLOCATE_REQUEST))
462                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Allocated, true));
463         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.FREE_AVAILABLE))
464                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Available, true));
465 
466         DeviceManager manager = createDeviceManager(null);
467         mDeviceListener.deviceConnected(mMockIDevice);
468         assertNotNull(manager.allocateDevice(mDeviceSelections));
469         manager.freeDevice(mMockTestDevice, FreeDeviceState.AVAILABLE);
470 
471         verify(mMockTestDevice).stopLogcat();
472     }
473 
474     /**
475      * Verified that {@link DeviceManager#freeDevice(ITestDevice, FreeDeviceState)} ignores a call
476      * with a device that has not been allocated.
477      */
478     @Test
testFreeDevice_noop()479     public void testFreeDevice_noop() {
480         setCheckAvailableDeviceExpectations();
481         IManagedTestDevice testDevice = mock(IManagedTestDevice.class);
482         IDevice mockIDevice = mock(IDevice.class);
483         when(testDevice.getIDevice()).thenReturn(mockIDevice);
484         when(mockIDevice.isEmulator()).thenReturn(Boolean.FALSE);
485 
486         DeviceManager manager = createDeviceManager(null, mMockIDevice);
487         manager.freeDevice(testDevice, FreeDeviceState.AVAILABLE);
488     }
489 
490     /**
491      * Verified that {@link DeviceManager} calls {@link IManagedTestDevice#setIDevice(IDevice)} when
492      * DDMS allocates a new IDevice on connection.
493      */
494     @Test
testSetIDevice()495     public void testSetIDevice() {
496         setCheckAvailableDeviceExpectations();
497         when(mMockTestDevice.getAllocationState()).thenReturn(DeviceAllocationState.Available);
498         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.ALLOCATE_REQUEST))
499                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Allocated, true));
500         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.DISCONNECTED))
501                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Allocated, false));
502         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.CONNECTED_ONLINE))
503                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Allocated, false));
504         IDevice newMockDevice = mock(IDevice.class);
505         when(newMockDevice.getSerialNumber()).thenReturn(DEVICE_SERIAL);
506         when(newMockDevice.getState()).thenReturn(DeviceState.ONLINE);
507 
508         DeviceManager manager = createDeviceManager(null, mMockIDevice);
509         ITestDevice device = manager.allocateDevice(mDeviceSelections);
510         assertNotNull(device);
511         // now trigger a device disconnect + reconnection
512         mDeviceListener.deviceDisconnected(mMockIDevice);
513         mDeviceListener.deviceConnected(newMockDevice);
514         assertEquals(newMockDevice, device.getIDevice());
515 
516         verify(mMockTestDevice, times(1)).setDeviceState(TestDeviceState.NOT_AVAILABLE);
517         verify(mMockTestDevice, times(2)).setDeviceState(TestDeviceState.ONLINE);
518     }
519 
520     /**
521      * Test {@link DeviceManager#allocateDevice()} when {@link DeviceManager#init()} has not been
522      * called.
523      */
524     @Test
testAllocateDevice_noInit()525     public void testAllocateDevice_noInit() {
526         try {
527             createDeviceManagerNoInit().allocateDevice(mDeviceSelections);
528             fail("IllegalStateException not thrown when manager has not been initialized");
529         } catch (IllegalStateException e) {
530             // expected
531         }
532     }
533 
534     /** Test {@link DeviceManager#init(IDeviceSelection, List)} with a global exclusion filter */
535     @Test
testInit_excludeDevice()536     public void testInit_excludeDevice() throws Exception {
537         when(mMockIDevice.getState()).thenReturn(DeviceState.ONLINE);
538 
539         DeviceEventResponse der =
540                 new DeviceEventResponse(DeviceAllocationState.Checking_Availability, true);
541         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.CONNECTED_ONLINE)).thenReturn(der);
542         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.AVAILABLE_CHECK_IGNORED))
543                 .thenReturn(null);
544         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.ALLOCATE_REQUEST))
545                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Ignored, false));
546 
547         DeviceManager manager = createDeviceManagerNoInit();
548         DeviceSelectionOptions excludeFilter = new DeviceSelectionOptions();
549         excludeFilter.addExcludeSerial(mMockIDevice.getSerialNumber());
550         manager.init(excludeFilter, null, mMockDeviceFactory);
551         mDeviceListener.deviceConnected(mMockIDevice);
552         assertEquals(1, manager.getDeviceList().size());
553         assertNull(manager.allocateDevice(mDeviceSelections));
554         verify(mMockTestDevice, times(1)).setDeviceState(TestDeviceState.ONLINE);
555     }
556 
557     /** Test {@link DeviceManager#init(IDeviceSelection, List)} with a global inclusion filter */
558     @Test
testInit_includeDevice()559     public void testInit_includeDevice() throws Exception {
560         IDevice excludedDevice = mock(IDevice.class);
561         when(excludedDevice.getSerialNumber()).thenReturn("excluded");
562         when(excludedDevice.getState()).thenReturn(DeviceState.ONLINE);
563         when(mMockIDevice.getState()).thenReturn(DeviceState.ONLINE);
564         when(excludedDevice.isEmulator()).thenReturn(Boolean.FALSE);
565 
566         DeviceEventResponse der =
567                 new DeviceEventResponse(DeviceAllocationState.Checking_Availability, true);
568         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.CONNECTED_ONLINE)).thenReturn(der);
569         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.AVAILABLE_CHECK_IGNORED))
570                 .thenReturn(null);
571         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.ALLOCATE_REQUEST))
572                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Ignored, false));
573 
574         DeviceManager manager = createDeviceManagerNoInit();
575         mDeviceSelections.addSerial(mMockIDevice.getSerialNumber());
576         manager.init(mDeviceSelections, null, mMockDeviceFactory);
577         mDeviceListener.deviceConnected(excludedDevice);
578         assertEquals(1, manager.getDeviceList().size());
579         // ensure excludedDevice cannot be allocated
580         assertNull(manager.allocateDevice());
581 
582         verify(mMockTestDevice).setDeviceState(TestDeviceState.ONLINE);
583     }
584 
585     /** Verified that a disconnected device state gets updated */
586     @Test
testSetState_disconnected()587     public void testSetState_disconnected() {
588         setCheckAvailableDeviceExpectations();
589         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.ALLOCATE_REQUEST))
590                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Allocated, true));
591         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.DISCONNECTED))
592                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Allocated, false));
593 
594         DeviceManager manager = createDeviceManager(null, mMockIDevice);
595         assertEquals(mMockTestDevice, manager.allocateDevice(mDeviceSelections));
596         mDeviceListener.deviceDisconnected(mMockIDevice);
597 
598         verify(mMockTestDevice).setDeviceState(TestDeviceState.NOT_AVAILABLE);
599     }
600 
601     /** Verified that a offline device state gets updated */
602     @Test
testSetState_offline()603     public void testSetState_offline() {
604         setCheckAvailableDeviceExpectations();
605         when(mMockTestDevice.getAllocationState()).thenReturn(DeviceAllocationState.Allocated);
606         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.ALLOCATE_REQUEST))
607                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Allocated, true));
608 
609         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.STATE_CHANGE_OFFLINE))
610                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Unavailable, true));
611 
612         DeviceManager manager = createDeviceManager(null, mMockIDevice);
613         assertEquals(mMockTestDevice, manager.allocateDevice(mDeviceSelections));
614         IDevice newDevice = mock(IDevice.class);
615         when(newDevice.getSerialNumber()).thenReturn(DEVICE_SERIAL);
616         when(newDevice.getState()).thenReturn(DeviceState.OFFLINE);
617 
618         mDeviceListener.deviceChanged(newDevice, IDevice.CHANGE_STATE);
619 
620         verify(mMockTestDevice).setDeviceState(TestDeviceState.NOT_AVAILABLE);
621 
622         verify(newDevice, times(2)).getState();
623     }
624 
625     // TODO: add test for fastboot state changes
626 
627     /** Test normal success case for {@link DeviceManager#connectToTcpDevice(String)} */
628     @Test
testConnectToTcpDevice()629     public void testConnectToTcpDevice() throws Exception {
630         final String ipAndPort = "ip:5555";
631         setConnectToTcpDeviceExpectations(ipAndPort);
632 
633         DeviceManager manager = createDeviceManager(null);
634         IManagedTestDevice device = (IManagedTestDevice) manager.connectToTcpDevice(ipAndPort);
635         assertNotNull(device);
636 
637         verify(mMockTestDevice).waitForDeviceOnline();
638     }
639 
640     /**
641      * Test a {@link DeviceManager#connectToTcpDevice(String)} call where device is already
642      * allocated
643      */
644     @Test
testConnectToTcpDevice_alreadyAllocated()645     public void testConnectToTcpDevice_alreadyAllocated() throws Exception {
646         final String ipAndPort = "ip:5555";
647         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.FORCE_ALLOCATE_REQUEST))
648                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Allocated, true))
649                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Allocated, false));
650         CommandResult connectResult = new CommandResult(CommandStatus.SUCCESS);
651         connectResult.setStdout(String.format("connected to %s", ipAndPort));
652         when(mMockRunUtil.runTimedCmd(
653                         Mockito.anyLong(),
654                         Mockito.eq("adb"),
655                         Mockito.eq("connect"),
656                         Mockito.eq(ipAndPort)))
657                 .thenReturn(connectResult);
658 
659         when(mMockTestDevice.getAllocationState()).thenReturn(DeviceAllocationState.Allocated);
660 
661         DeviceManager manager = createDeviceManager(null);
662         IManagedTestDevice device = (IManagedTestDevice) manager.connectToTcpDevice(ipAndPort);
663         assertNotNull(device);
664         // now attempt to re-allocate
665         assertNull(manager.connectToTcpDevice(ipAndPort));
666 
667         verify(mMockTestDevice).waitForDeviceOnline();
668     }
669 
670     /** Test {@link DeviceManager#connectToTcpDevice(String)} where device does not appear on adb */
671     @Test
testConnectToTcpDevice_notOnline()672     public void testConnectToTcpDevice_notOnline() throws Exception {
673         final String ipAndPort = "ip:5555";
674         setConnectToTcpDeviceExpectations(ipAndPort);
675         doThrow(new DeviceNotAvailableException("test", "serial"))
676                 .when(mMockTestDevice)
677                 .waitForDeviceOnline();
678 
679         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.FREE_UNKNOWN))
680                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Unknown, false));
681 
682         DeviceManager manager = createDeviceManager(null);
683         assertNull(manager.connectToTcpDevice(ipAndPort));
684         // verify device is not in list
685         assertEquals(0, manager.getDeviceList().size());
686 
687         verify(mMockTestDevice).stopLogcat();
688     }
689 
690     /** Test {@link DeviceManager#connectToTcpDevice(String)} where the 'adb connect' call fails. */
691     @Test
testConnectToTcpDevice_connectFailed()692     public void testConnectToTcpDevice_connectFailed() throws Exception {
693         final String ipAndPort = "ip:5555";
694 
695         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.FORCE_ALLOCATE_REQUEST))
696                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Allocated, true));
697         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.FREE_UNKNOWN))
698                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Unknown, true));
699         CommandResult connectResult = new CommandResult(CommandStatus.SUCCESS);
700         connectResult.setStdout(String.format("failed to connect to %s", ipAndPort));
701         when(mMockRunUtil.runTimedCmd(
702                         Mockito.anyLong(),
703                         Mockito.eq("adb"),
704                         Mockito.eq("connect"),
705                         Mockito.eq(ipAndPort)))
706                 .thenReturn(connectResult);
707 
708         DeviceManager manager = createDeviceManager(null);
709         assertNull(manager.connectToTcpDevice(ipAndPort));
710         // verify device is not in list
711         assertEquals(0, manager.getDeviceList().size());
712         verify(mMockRunUtil, times(3)).sleep(Mockito.anyLong());
713         verify(mMockRunUtil, times(3))
714                 .runTimedCmd(
715                         Mockito.anyLong(),
716                         Mockito.eq("adb"),
717                         Mockito.eq("connect"),
718                         Mockito.eq(ipAndPort));
719         verify(mMockTestDevice).stopLogcat();
720     }
721 
722     /** Test normal success case for {@link DeviceManager#disconnectFromTcpDevice(ITestDevice)} */
723     @Test
testDisconnectFromTcpDevice()724     public void testDisconnectFromTcpDevice() throws Exception {
725         final String ipAndPort = "ip:5555";
726         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.FREE_UNKNOWN))
727                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Unknown, true));
728         setConnectToTcpDeviceExpectations(ipAndPort);
729         when(mMockTestDevice.switchToAdbUsb()).thenReturn(Boolean.TRUE);
730 
731         DeviceManager manager = createDeviceManager(null);
732         assertNotNull(manager.connectToTcpDevice(ipAndPort));
733         manager.disconnectFromTcpDevice(mMockTestDevice);
734         // verify device is not in allocated or available list
735         assertEquals(0, manager.getDeviceList().size());
736 
737         verify(mMockTestDevice).waitForDeviceOnline();
738         verify(mMockTestDevice).stopLogcat();
739     }
740 
741     /** Test normal success case for {@link DeviceManager#reconnectDeviceToTcp(ITestDevice)}. */
742     @Test
testReconnectDeviceToTcp()743     public void testReconnectDeviceToTcp() throws Exception {
744         final String ipAndPort = "ip:5555";
745         // use the mMockTestDevice as the initially connected to usb device
746         setCheckAvailableDeviceExpectations();
747         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.ALLOCATE_REQUEST))
748                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Allocated, true));
749         when(mMockTestDevice.switchToAdbTcp()).thenReturn(ipAndPort);
750         setConnectToTcpDeviceExpectations(ipAndPort);
751 
752         DeviceManager manager = createDeviceManager(null, mMockIDevice);
753         assertEquals(mMockTestDevice, manager.allocateDevice(mDeviceSelections));
754         assertNotNull(manager.reconnectDeviceToTcp(mMockTestDevice));
755 
756         verify(mMockTestDevice).waitForDeviceOnline();
757     }
758 
759     /**
760      * Test {@link DeviceManager#reconnectDeviceToTcp(ITestDevice)} when tcp connected device does
761      * not come online.
762      */
763     @Test
testReconnectDeviceToTcp_notOnline()764     public void testReconnectDeviceToTcp_notOnline() throws Exception {
765         final String ipAndPort = "ip:5555";
766         // use the mMockTestDevice as the initially connected to usb device
767         setCheckAvailableDeviceExpectations();
768         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.ALLOCATE_REQUEST))
769                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Allocated, true));
770         when(mMockTestDevice.switchToAdbTcp()).thenReturn(ipAndPort);
771         setConnectToTcpDeviceExpectations(ipAndPort);
772         doThrow(new DeviceNotAvailableException("test", "serial"))
773                 .when(mMockTestDevice)
774                 .waitForDeviceOnline();
775         // expect recover to be attempted on usb device
776 
777         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.FREE_UNKNOWN))
778                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Unknown, true));
779 
780         DeviceManager manager = createDeviceManager(null, mMockIDevice);
781         assertEquals(mMockTestDevice, manager.allocateDevice(mDeviceSelections));
782         assertNull(manager.reconnectDeviceToTcp(mMockTestDevice));
783         // verify only usb device is in list
784         assertEquals(1, manager.getDeviceList().size());
785 
786         verify(mMockTestDevice).recoverDevice();
787         verify(mMockTestDevice).stopLogcat();
788     }
789 
790     /** Basic test for {@link DeviceManager#sortDeviceList(List)} */
791     @Test
testSortDeviceList()792     public void testSortDeviceList() {
793         DeviceDescriptor availDevice1 = createDeviceDesc("aaa", DeviceAllocationState.Available);
794         DeviceDescriptor availDevice2 = createDeviceDesc("bbb", DeviceAllocationState.Available);
795         DeviceDescriptor allocatedDevice = createDeviceDesc("ccc", DeviceAllocationState.Allocated);
796         List<DeviceDescriptor> deviceList =
797                 ArrayUtil.list(availDevice1, availDevice2, allocatedDevice);
798         List<DeviceDescriptor> sortedList = DeviceManager.sortDeviceList(deviceList);
799         assertEquals(allocatedDevice, sortedList.get(0));
800         assertEquals(availDevice1, sortedList.get(1));
801         assertEquals(availDevice2, sortedList.get(2));
802     }
803 
804     /** Helper method to create a {@link DeviceDescriptor} using only serial and state. */
createDeviceDesc(String serial, DeviceAllocationState state)805     private DeviceDescriptor createDeviceDesc(String serial, DeviceAllocationState state) {
806         return new DeviceDescriptor(serial, false, state, null, null, null, null, null);
807     }
808 
809     /**
810      * Set expectations for a successful {@link DeviceManager#connectToTcpDevice(String)}
811      * call.
812      *
813      * @param ipAndPort the ip and port of the device
814      * @throws DeviceNotAvailableException
815      */
setConnectToTcpDeviceExpectations(final String ipAndPort)816     private void setConnectToTcpDeviceExpectations(final String ipAndPort)
817             throws DeviceNotAvailableException {
818         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.FORCE_ALLOCATE_REQUEST))
819                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Allocated, true));
820         mMockTestDevice.setRecovery((IDeviceRecovery) Mockito.any());
821         CommandResult connectResult = new CommandResult(CommandStatus.SUCCESS);
822         connectResult.setStdout(String.format("connected to %s", ipAndPort));
823         when(mMockRunUtil.runTimedCmd(
824                         Mockito.anyLong(),
825                         Mockito.eq("adb"),
826                         Mockito.eq("connect"),
827                         Mockito.eq(ipAndPort)))
828                 .thenReturn(connectResult);
829     }
830 
831     /**
832      * Configure expectations for a {@link
833      * DeviceManager#checkAndAddAvailableDevice(IManagedTestDevice)} call for an online device
834      */
835     @SuppressWarnings("javadoc")
setCheckAvailableDeviceExpectations()836     private void setCheckAvailableDeviceExpectations() {
837         setCheckAvailableDeviceExpectations(mMockIDevice);
838     }
839 
setCheckAvailableDeviceExpectations(IDevice iDevice)840     private void setCheckAvailableDeviceExpectations(IDevice iDevice) {
841         when(mMockIDevice.isEmulator()).thenReturn(Boolean.FALSE);
842         when(iDevice.getState()).thenReturn(DeviceState.ONLINE);
843         when(mMockStateMonitor.waitForDeviceShell(Mockito.anyLong())).thenReturn(Boolean.TRUE);
844         when(mMockTestDevice.getDeviceState()).thenReturn(TestDeviceState.ONLINE);
845         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.CONNECTED_ONLINE))
846                 .thenReturn(
847                         new DeviceEventResponse(DeviceAllocationState.Checking_Availability, true));
848         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.AVAILABLE_CHECK_PASSED))
849                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Available, true));
850     }
851 
852     /** Test freeing a tcp device, it must return to an unavailable status */
853     @Test
testFreeDevice_tcpDevice()854     public void testFreeDevice_tcpDevice() {
855         mDeviceSelections.setGceDeviceRequested(true);
856         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.FORCE_AVAILABLE))
857                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Available, true));
858         when(mMockIDevice.isEmulator()).thenReturn(Boolean.FALSE);
859         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.ALLOCATE_REQUEST))
860                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Allocated, true));
861 
862         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.ALLOCATE_REQUEST))
863                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Allocated, true));
864         when(mMockTestDevice.getDeviceState()).thenReturn(TestDeviceState.NOT_AVAILABLE);
865         when(mMockTestDevice.handleAllocationEvent(DeviceEvent.FREE_UNKNOWN))
866                 .thenReturn(new DeviceEventResponse(DeviceAllocationState.Available, true));
867 
868         DeviceManager manager = createDeviceManagerNoInit();
869         manager.setMaxGceDevices(1);
870         manager.init(null, null, mMockDeviceFactory);
871         IManagedTestDevice tcpDevice =
872                 (IManagedTestDevice) manager.allocateDevice(mDeviceSelections, false);
873         assertNotNull(tcpDevice);
874         // a freed 'unavailable' emulator should be returned to the available
875         // queue.
876         manager.freeDevice(tcpDevice, FreeDeviceState.UNAVAILABLE);
877         // ensure device can be allocated again
878         ITestDevice tcp = manager.allocateDevice(mDeviceSelections, false);
879         assertNotNull(tcp);
880         assertTrue(tcp.getDeviceState() == TestDeviceState.NOT_AVAILABLE);
881         verify(mMockTestDevice, times(2)).getDeviceState();
882         verify(mMockTestDevice).stopLogcat();
883         verify(mMockTestDevice).setDeviceState(TestDeviceState.NOT_AVAILABLE);
884     }
885 
886     /**
887      * Test freeing a device that was unable but showing in adb devices. Device will become
888      * Unavailable but still seen by the DeviceManager.
889      */
890     @Test
testFreeDevice_unavailable()891     public void testFreeDevice_unavailable() {
892         when(mMockIDevice.isEmulator()).thenReturn(Boolean.FALSE);
893         when(mMockIDevice.getState()).thenReturn(DeviceState.ONLINE);
894         when(mMockStateMonitor.waitForDeviceShell(Mockito.anyLong())).thenReturn(Boolean.TRUE);
895 
896         CommandResult stubAdbDevices = new CommandResult(CommandStatus.SUCCESS);
897         stubAdbDevices.setStdout("List of devices attached\nserial\toffline\n");
898         when(mMockRunUtil.runTimedCmd(Mockito.anyLong(), Mockito.eq("adb"), Mockito.eq("devices")))
899                 .thenReturn(stubAdbDevices);
900 
901         IManagedTestDevice testDevice = new TestDevice(mMockIDevice, mMockStateMonitor, null);
902         DeviceManager manager = createDeviceManagerNoInit();
903         manager.init(
904                 null,
905                 null,
906                 new ManagedTestDeviceFactory(false, null, null) {
907                     @Override
908                     public IManagedTestDevice createDevice(IDevice idevice) {
909                         mMockTestDevice.setIDevice(idevice);
910                         return testDevice;
911                     }
912 
913                     @Override
914                     protected CollectingOutputReceiver createOutputReceiver() {
915                         return new CollectingOutputReceiver() {
916                             @Override
917                             public String getOutput() {
918                                 return "/system/bin/pm";
919                             }
920                         };
921                     }
922 
923                     @Override
924                     public void setFastbootEnabled(boolean enable) {
925                         // ignore
926                     }
927                 });
928 
929         mDeviceListener.deviceConnected(mMockIDevice);
930 
931         IManagedTestDevice device = (IManagedTestDevice) manager.allocateDevice(mDeviceSelections);
932         assertNotNull(device);
933         // device becomes unavailable
934         device.setDeviceState(TestDeviceState.NOT_AVAILABLE);
935         // a freed 'unavailable' device becomes UNAVAILABLE state
936         manager.freeDevice(device, FreeDeviceState.UNAVAILABLE);
937         // ensure device cannot be allocated again
938         ITestDevice device2 = manager.allocateDevice(mDeviceSelections);
939         assertNull(device2);
940 
941         verify(mMockStateMonitor).setState(TestDeviceState.NOT_AVAILABLE);
942 
943         // We still have the device in the list
944         assertEquals(1, manager.getDeviceList().size());
945     }
946 
947     /** Ensure that an unavailable device in recovery mode is released properly. */
948     @Test
testFreeDevice_recovery()949     public void testFreeDevice_recovery() {
950         when(mMockIDevice.isEmulator()).thenReturn(Boolean.FALSE);
951         when(mMockIDevice.getState()).thenReturn(DeviceState.ONLINE);
952         when(mMockStateMonitor.waitForDeviceShell(Mockito.anyLong())).thenReturn(Boolean.TRUE);
953 
954         CommandResult stubAdbDevices = new CommandResult(CommandStatus.SUCCESS);
955         stubAdbDevices.setStdout("List of devices attached\nserial\trecovery\n");
956         when(mMockRunUtil.runTimedCmd(Mockito.anyLong(), Mockito.eq("adb"), Mockito.eq("devices")))
957                 .thenReturn(stubAdbDevices);
958 
959         IManagedTestDevice testDevice = new TestDevice(mMockIDevice, mMockStateMonitor, null);
960         DeviceManager manager = createDeviceManagerNoInit();
961         manager.init(
962                 null,
963                 null,
964                 new ManagedTestDeviceFactory(false, null, null) {
965                     @Override
966                     public IManagedTestDevice createDevice(IDevice idevice) {
967                         mMockTestDevice.setIDevice(idevice);
968                         return testDevice;
969                     }
970 
971                     @Override
972                     protected CollectingOutputReceiver createOutputReceiver() {
973                         return new CollectingOutputReceiver() {
974                             @Override
975                             public String getOutput() {
976                                 return "/system/bin/pm";
977                             }
978                         };
979                     }
980 
981                     @Override
982                     public void setFastbootEnabled(boolean enable) {
983                         // ignore
984                     }
985                 });
986 
987         mDeviceListener.deviceConnected(mMockIDevice);
988 
989         IManagedTestDevice device = (IManagedTestDevice) manager.allocateDevice(mDeviceSelections);
990         assertNotNull(device);
991         // Device becomes unavailable
992         device.setDeviceState(TestDeviceState.NOT_AVAILABLE);
993         // A freed 'unavailable' device becomes UNAVAILABLE state
994         manager.freeDevice(device, FreeDeviceState.UNAVAILABLE);
995         // Ensure device cannot be allocated again
996         ITestDevice device2 = manager.allocateDevice(mDeviceSelections);
997         assertNull(device2);
998 
999         verify(mMockStateMonitor).setState(TestDeviceState.NOT_AVAILABLE);
1000 
1001         // We still have the device in the list because device is not lost.
1002         assertEquals(1, manager.getDeviceList().size());
1003     }
1004 
1005     /**
1006      * Test that when freeing an Unavailable device that is not in 'adb devices' we correctly remove
1007      * it from our tracking list.
1008      */
1009     @Test
testFreeDevice_unknown()1010     public void testFreeDevice_unknown() {
1011         when(mMockIDevice.isEmulator()).thenReturn(Boolean.FALSE);
1012         when(mMockIDevice.getState()).thenReturn(DeviceState.ONLINE);
1013         when(mMockStateMonitor.waitForDeviceShell(Mockito.anyLong())).thenReturn(Boolean.TRUE);
1014 
1015         CommandResult stubAdbDevices = new CommandResult(CommandStatus.SUCCESS);
1016         // device serial is not in the list
1017         stubAdbDevices.setStdout("List of devices attached\n");
1018         when(mMockRunUtil.runTimedCmd(Mockito.anyLong(), Mockito.eq("adb"), Mockito.eq("devices")))
1019                 .thenReturn(stubAdbDevices);
1020 
1021         IManagedTestDevice testDevice = new TestDevice(mMockIDevice, mMockStateMonitor, null);
1022         DeviceManager manager = createDeviceManagerNoInit();
1023         manager.init(
1024                 null,
1025                 null,
1026                 new ManagedTestDeviceFactory(false, null, null) {
1027                     @Override
1028                     public IManagedTestDevice createDevice(IDevice idevice) {
1029                         mMockTestDevice.setIDevice(idevice);
1030                         return testDevice;
1031                     }
1032 
1033                     @Override
1034                     protected CollectingOutputReceiver createOutputReceiver() {
1035                         return new CollectingOutputReceiver() {
1036                             @Override
1037                             public String getOutput() {
1038                                 return "/system/bin/pm";
1039                             }
1040                         };
1041                     }
1042 
1043                     @Override
1044                     public void setFastbootEnabled(boolean enable) {
1045                         // ignore
1046                     }
1047                 });
1048 
1049         mDeviceListener.deviceConnected(mMockIDevice);
1050 
1051         IManagedTestDevice device = (IManagedTestDevice) manager.allocateDevice(mDeviceSelections);
1052         assertNotNull(device);
1053         // device becomes unavailable
1054         device.setDeviceState(TestDeviceState.NOT_AVAILABLE);
1055         // a freed 'unavailable' device becomes UNAVAILABLE state
1056         manager.freeDevice(device, FreeDeviceState.UNAVAILABLE);
1057         // ensure device cannot be allocated again
1058         ITestDevice device2 = manager.allocateDevice(mDeviceSelections);
1059         assertNull(device2);
1060 
1061         verify(mMockStateMonitor).setState(TestDeviceState.NOT_AVAILABLE);
1062 
1063         // We have 0 device in the list since it was removed
1064         assertEquals(0, manager.getDeviceList().size());
1065     }
1066 
1067     /**
1068      * Test that when freeing an Unavailable device that is not in 'adb devices' we correctly remove
1069      * it from our tracking list even if its serial is a substring of another serial.
1070      */
1071     @Test
testFreeDevice_unknown_subName()1072     public void testFreeDevice_unknown_subName() {
1073         when(mMockIDevice.isEmulator()).thenReturn(Boolean.FALSE);
1074         when(mMockIDevice.getState()).thenReturn(DeviceState.ONLINE);
1075         when(mMockStateMonitor.waitForDeviceShell(Mockito.anyLong())).thenReturn(Boolean.TRUE);
1076 
1077         CommandResult stubAdbDevices = new CommandResult(CommandStatus.SUCCESS);
1078         // device serial is not in the list
1079         stubAdbDevices.setStdout("List of devices attached\n2serial\tdevice\n");
1080         when(mMockRunUtil.runTimedCmd(Mockito.anyLong(), Mockito.eq("adb"), Mockito.eq("devices")))
1081                 .thenReturn(stubAdbDevices);
1082 
1083         IManagedTestDevice testDevice = new TestDevice(mMockIDevice, mMockStateMonitor, null);
1084         DeviceManager manager = createDeviceManagerNoInit();
1085         manager.init(
1086                 null,
1087                 null,
1088                 new ManagedTestDeviceFactory(false, null, null) {
1089                     @Override
1090                     public IManagedTestDevice createDevice(IDevice idevice) {
1091                         mMockTestDevice.setIDevice(idevice);
1092                         return testDevice;
1093                     }
1094 
1095                     @Override
1096                     protected CollectingOutputReceiver createOutputReceiver() {
1097                         return new CollectingOutputReceiver() {
1098                             @Override
1099                             public String getOutput() {
1100                                 return "/system/bin/pm";
1101                             }
1102                         };
1103                     }
1104 
1105                     @Override
1106                     public void setFastbootEnabled(boolean enable) {
1107                         // ignore
1108                     }
1109                 });
1110 
1111         mDeviceListener.deviceConnected(mMockIDevice);
1112 
1113         IManagedTestDevice device = (IManagedTestDevice) manager.allocateDevice(mDeviceSelections);
1114         assertNotNull(device);
1115         // device becomes unavailable
1116         device.setDeviceState(TestDeviceState.NOT_AVAILABLE);
1117         // a freed 'unavailable' device becomes UNAVAILABLE state
1118         manager.freeDevice(device, FreeDeviceState.UNAVAILABLE);
1119         // ensure device cannot be allocated again
1120         ITestDevice device2 = manager.allocateDevice(mDeviceSelections);
1121         assertNull(device2);
1122 
1123         verify(mMockStateMonitor).setState(TestDeviceState.NOT_AVAILABLE);
1124 
1125         // We have 0 device in the list since it was removed
1126         assertEquals(0, manager.getDeviceList().size());
1127     }
1128 
1129     /** Helper to set the expectation when a {@link DeviceDescriptor} is expected. */
setDeviceDescriptorExpectation(boolean cached)1130     private void setDeviceDescriptorExpectation(boolean cached) {
1131         DeviceDescriptor descriptor =
1132                 new DeviceDescriptor(
1133                         "serial",
1134                         null,
1135                         false,
1136                         DeviceState.ONLINE,
1137                         DeviceAllocationState.Available,
1138                         TestDeviceState.ONLINE,
1139                         "hardware_test",
1140                         "product_test",
1141                         "sdk",
1142                         "bid_test",
1143                         null,
1144                         "50",
1145                         "class",
1146                         MAC_ADDRESS,
1147                         SIM_STATE,
1148                         SIM_OPERATOR,
1149                         false,
1150                         null,
1151                         null,
1152                         null);
1153         if (cached) {
1154             when(mMockTestDevice.getCachedDeviceDescriptor(false)).thenReturn(descriptor);
1155         } else {
1156             when(mMockTestDevice.getDeviceDescriptor(false)).thenReturn(descriptor);
1157         }
1158     }
1159 
1160     /** Test that {@link DeviceManager#listAllDevices()} returns a list with all devices. */
1161     @Test
testListAllDevices()1162     public void testListAllDevices() throws Exception {
1163         setCheckAvailableDeviceExpectations();
1164         setDeviceDescriptorExpectation(true);
1165 
1166         DeviceManager manager = createDeviceManager(null, mMockIDevice);
1167         List<DeviceDescriptor> res = manager.listAllDevices();
1168         assertEquals(1, res.size());
1169         assertEquals("[serial hardware_test:product_test bid_test]", res.get(0).toString());
1170         assertEquals(MAC_ADDRESS, res.get(0).getMacAddress());
1171         assertEquals(SIM_STATE, res.get(0).getSimState());
1172         assertEquals(SIM_OPERATOR, res.get(0).getSimOperator());
1173     }
1174 
1175     /**
1176      * Test {@link DeviceManager#getDeviceDescriptor(String)} returns the device with the given
1177      * serial.
1178      */
1179     @Test
testGetDeviceDescriptor()1180     public void testGetDeviceDescriptor() throws Exception {
1181         setCheckAvailableDeviceExpectations();
1182         setDeviceDescriptorExpectation(false);
1183 
1184         DeviceManager manager = createDeviceManager(null, mMockIDevice);
1185         DeviceDescriptor res = manager.getDeviceDescriptor(mMockIDevice.getSerialNumber());
1186         assertEquals("[serial hardware_test:product_test bid_test]", res.toString());
1187         assertEquals(MAC_ADDRESS, res.getMacAddress());
1188         assertEquals(SIM_STATE, res.getSimState());
1189         assertEquals(SIM_OPERATOR, res.getSimOperator());
1190     }
1191 
1192     /**
1193      * Test that {@link DeviceManager#getDeviceDescriptor(String)} returns null if there are no
1194      * devices with the given serial.
1195      */
1196     @Test
testGetDeviceDescriptor_noMatch()1197     public void testGetDeviceDescriptor_noMatch() throws Exception {
1198         setCheckAvailableDeviceExpectations();
1199 
1200         DeviceManager manager = createDeviceManager(null, mMockIDevice);
1201         DeviceDescriptor res = manager.getDeviceDescriptor("nomatch");
1202         assertNull(res);
1203     }
1204 
1205     /**
1206      * Test that {@link DeviceManager#displayDevicesInfo(PrintWriter, boolean)} properly print out
1207      * the device info.
1208      */
1209     @Test
testDisplayDevicesInfo()1210     public void testDisplayDevicesInfo() throws Exception {
1211         setCheckAvailableDeviceExpectations();
1212         setDeviceDescriptorExpectation(true);
1213 
1214         DeviceManager manager = createDeviceManager(null, mMockIDevice);
1215         ByteArrayOutputStream out = new ByteArrayOutputStream();
1216         PrintWriter pw = new PrintWriter(out);
1217         manager.displayDevicesInfo(pw, false);
1218         pw.flush();
1219 
1220         assertEquals(
1221                 "Serial  State   Allocation  Product        Variant       Build     Battery  \n"
1222                     + "serial  ONLINE  Available   hardware_test  product_test  bid_test  50      "
1223                     + " \n",
1224                 out.toString());
1225     }
1226 
1227     /**
1228      * Test that {@link DeviceManager#shouldAdbBridgeBeRestarted()} properly reports the flag state
1229      * based on if it was requested or not.
1230      */
1231     @Test
testAdbBridgeFlag()1232     public void testAdbBridgeFlag() throws Exception {
1233         setCheckAvailableDeviceExpectations();
1234 
1235         DeviceManager manager = createDeviceManager(null, mMockIDevice);
1236 
1237         assertFalse(manager.shouldAdbBridgeBeRestarted());
1238         manager.stopAdbBridge();
1239         assertTrue(manager.shouldAdbBridgeBeRestarted());
1240         manager.restartAdbBridge();
1241         assertFalse(manager.shouldAdbBridgeBeRestarted());
1242     }
1243 
1244     /**
1245      * Test that when a {@link IDeviceMonitor} is available in {@link DeviceManager} it properly
1246      * goes through its life cycle.
1247      */
1248     @Test
testDeviceMonitorLifeCycle()1249     public void testDeviceMonitorLifeCycle() throws Exception {
1250         IDeviceMonitor mockMonitor = mock(IDeviceMonitor.class);
1251         List<IDeviceMonitor> monitors = new ArrayList<>();
1252         monitors.add(mockMonitor);
1253         setCheckAvailableDeviceExpectations();
1254 
1255         DeviceManager manager = createDeviceManager(monitors, mMockIDevice);
1256         manager.terminateDeviceMonitor();
1257 
1258         verify(mockMonitor).setDeviceLister(Mockito.any());
1259         verify(mockMonitor).run();
1260         verify(mockMonitor).stop();
1261     }
1262 
1263     /** Ensure that restarting adb bridge doesn't restart {@link IDeviceMonitor}. */
1264     @Test
testDeviceMonitorLifeCycleWhenAdbRestarts()1265     public void testDeviceMonitorLifeCycleWhenAdbRestarts() throws Exception {
1266         IDeviceMonitor mockMonitor = mock(IDeviceMonitor.class);
1267         List<IDeviceMonitor> monitors = new ArrayList<>();
1268         monitors.add(mockMonitor);
1269         setCheckAvailableDeviceExpectations();
1270 
1271         DeviceManager manager = createDeviceManager(monitors, mMockIDevice);
1272         manager.stopAdbBridge();
1273         manager.restartAdbBridge();
1274         manager.terminateDeviceMonitor();
1275 
1276         verify(mockMonitor).setDeviceLister(Mockito.any());
1277         verify(mockMonitor).run();
1278         verify(mockMonitor).stop();
1279     }
1280 
1281     /** Test the command fails without execution when the device is not available. */
1282     @Test
testExecCmdOnAvailableDevice_deviceNotAvailable()1283     public void testExecCmdOnAvailableDevice_deviceNotAvailable() {
1284         setCheckAvailableDeviceExpectations();
1285         when(mMockTestDevice.getAllocationState()).thenReturn(DeviceAllocationState.Allocated);
1286 
1287         DeviceManager manager = createDeviceManager(null, mMockIDevice);
1288         CommandResult res =
1289                 manager.executeCmdOnAvailableDevice(
1290                         mMockTestDevice.getSerialNumber(), "mock cmd", 1, TimeUnit.SECONDS);
1291         assertEquals(CommandStatus.FAILED, res.getStatus());
1292         assertEquals(
1293                 "The device 'serial' is not available to execute the command", res.getStderr());
1294     }
1295 
1296     /** Test the command fails with long timeout. */
1297     @Test
testExecCmdOnAvailableDevice_longRunCmd()1298     public void testExecCmdOnAvailableDevice_longRunCmd() throws DeviceNotAvailableException {
1299         setCheckAvailableDeviceExpectations();
1300         when(mMockTestDevice.getAllocationState()).thenReturn(DeviceAllocationState.Available);
1301         when(mMockTestDevice.executeShellV2Command("foo", 2, TimeUnit.SECONDS))
1302                 .thenReturn(new CommandResult(CommandStatus.SUCCESS));
1303 
1304         DeviceManager manager = createDeviceManager(null, mMockIDevice);
1305         CommandResult res =
1306                 manager.executeCmdOnAvailableDevice(
1307                         mMockTestDevice.getSerialNumber(), "mock cmd", 2, TimeUnit.SECONDS);
1308         assertEquals(res.getStatus(), CommandStatus.FAILED);
1309         assertEquals(res.getStderr(), "The maximum timeout value is 1000 ms, but got 2000 ms.");
1310     }
1311 
1312     /** Test the command success. */
1313     @Test
testExecCmdOnAvailableDevice_success()1314     public void testExecCmdOnAvailableDevice_success() throws DeviceNotAvailableException {
1315         setCheckAvailableDeviceExpectations();
1316         when(mMockTestDevice.getAllocationState()).thenReturn(DeviceAllocationState.Available);
1317         when(mMockTestDevice.executeShellV2Command("foo", 1, TimeUnit.SECONDS))
1318                 .thenReturn(
1319                         new CommandResult() {
1320                             @Override
1321                             public CommandStatus getStatus() {
1322                                 return CommandStatus.SUCCESS;
1323                             }
1324 
1325                             @Override
1326                             public String getStdout() {
1327                                 return "bar";
1328                             }
1329                         });
1330 
1331         DeviceManager manager = createDeviceManager(null, mMockIDevice);
1332         CommandResult res =
1333                 manager.executeCmdOnAvailableDevice(
1334                         mMockTestDevice.getSerialNumber(), "foo", 1, TimeUnit.SECONDS);
1335         assertEquals(CommandStatus.SUCCESS, res.getStatus());
1336         assertEquals("bar", res.getStdout());
1337     }
1338 }
1339