1 /*
2  * Copyright (C) 2011 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 package com.android.tradefed.command.remote;
17 
18 import com.android.tradefed.build.BuildInfo;
19 import com.android.tradefed.command.ICommandScheduler;
20 import com.android.tradefed.command.ICommandScheduler.IScheduledInvocationListener;
21 import com.android.tradefed.device.DeviceAllocationState;
22 import com.android.tradefed.device.DeviceNotAvailableException;
23 import com.android.tradefed.device.FreeDeviceState;
24 import com.android.tradefed.device.IDeviceManager;
25 import com.android.tradefed.device.ITestDevice;
26 import com.android.tradefed.invoker.IInvocationContext;
27 import com.android.tradefed.invoker.InvocationContext;
28 
29 import junit.framework.TestCase;
30 
31 import java.util.ArrayList;
32 import java.util.Arrays;
33 import java.util.HashMap;
34 import java.util.List;
35 import java.util.Map;
36 
37 import org.easymock.EasyMock;
38 import org.easymock.IAnswer;
39 
40 /**
41  * Unit tests for {@link RemoteManager}.
42  */
43 public class RemoteManagerFuncTest extends TestCase {
44 
45     private IDeviceManager mMockDeviceManager;
46     private RemoteManager mRemoteMgr;
47     private IRemoteClient mRemoteClient;
48     private ICommandScheduler mMockScheduler;
49 
50     @Override
setUp()51     protected void setUp() throws Exception {
52         super.setUp();
53         mMockDeviceManager = EasyMock.createMock(IDeviceManager.class);
54         mMockScheduler = EasyMock.createMock(ICommandScheduler.class);
55         mRemoteMgr = new RemoteManager(mMockDeviceManager, mMockScheduler);
56         // Extra short timeout for testing.
57         mRemoteMgr.setRemoteManagerTimeout(100);
58     }
59 
60     @Override
tearDown()61     protected void tearDown() throws Exception {
62         if (mRemoteClient != null) {
63             mRemoteClient.close();
64         }
65         if (mRemoteMgr != null) {
66             mRemoteMgr.cancelAndWait();
67         }
68         super.tearDown();
69     }
70 
71     /**
72      * An integration test for client-manager interaction, that will allocate, then free a device.
73      */
testAllocateFree()74     public void testAllocateFree() throws Exception {
75         ITestDevice device = EasyMock.createMock(ITestDevice.class);
76         EasyMock.expect(device.getSerialNumber()).andStubReturn("serial");
77         EasyMock.expect(mMockDeviceManager.forceAllocateDevice("serial")).andReturn(device);
78         mMockDeviceManager.freeDevice(EasyMock.eq(device),
79                 EasyMock.eq(FreeDeviceState.AVAILABLE));
80 
81         EasyMock.replay(mMockDeviceManager, device);
82         mRemoteMgr.connectAnyPort();
83         mRemoteMgr.start();
84         int port = mRemoteMgr.getPort();
85         assertTrue(port != -1);
86         mRemoteClient = RemoteClient.connect(port);
87         mRemoteClient.sendAllocateDevice("serial");
88         mRemoteClient.sendFreeDevice("serial");
89         EasyMock.verify(mMockDeviceManager);
90     }
91 
92     /**
93      * An integration test for client-manager interaction, that will add a command
94      */
testAddCommand()95     public void testAddCommand() throws Exception {
96         EasyMock.expect(mMockScheduler.addCommand(EasyMock.aryEq(new String[] {
97                 "arg1", "arg2"
98         }), EasyMock.anyInt())).andReturn(true);
99 
100         EasyMock.replay(mMockScheduler);
101         mRemoteMgr.connectAnyPort();
102         mRemoteMgr.start();
103         int port = mRemoteMgr.getPort();
104         assertTrue(port != -1);
105         mRemoteClient = RemoteClient.connect(port);
106         mRemoteClient.sendAddCommand(3, "arg1", "arg2");
107         EasyMock.verify(mMockScheduler);
108     }
109 
110     /**
111      * An integration test for client-manager interaction, that will add a command file
112      */
testAddCommandFile()113     public void testAddCommandFile() throws Exception {
114         final String cmdFile = "cmd.txt";
115         List<String> extraArgs = Arrays.asList("foo", "bar");
116         mMockScheduler.addCommandFile(EasyMock.eq(cmdFile), EasyMock.eq(extraArgs));
117 
118         EasyMock.replay(mMockScheduler);
119         mRemoteMgr.connectAnyPort();
120         mRemoteMgr.start();
121         int port = mRemoteMgr.getPort();
122         assertTrue(port != -1);
123         mRemoteClient = RemoteClient.connect(port);
124         mRemoteClient.sendAddCommandFile(cmdFile, extraArgs);
125         EasyMock.verify(mMockScheduler);
126     }
127 
128     /**
129      * An integration test for client-manager interaction, that will allocate, then close the
130      * connection. Verifies that closing frees all devices.
131      */
132     @SuppressWarnings("deprecation")
testAllocateClose()133     public void testAllocateClose() throws Exception {
134         ITestDevice device = EasyMock.createMock(ITestDevice.class);
135         EasyMock.expect(device.getSerialNumber()).andStubReturn("serial");
136         EasyMock.expect(mMockDeviceManager.forceAllocateDevice("serial")).andReturn(device);
137         mMockDeviceManager.freeDevice(EasyMock.eq(device),
138                 EasyMock.eq(FreeDeviceState.AVAILABLE));
139 
140         EasyMock.replay(mMockDeviceManager, device);
141         mRemoteMgr.connectAnyPort();
142         mRemoteMgr.start();
143         int port = mRemoteMgr.getPort();
144         assertTrue(port != -1);
145         mRemoteClient = RemoteClient.connect(port);
146         mRemoteClient.sendAllocateDevice("serial");
147         mRemoteClient.sendClose();
148         mRemoteClient.close();
149         mRemoteMgr.join();
150         EasyMock.verify(mMockDeviceManager);
151     }
152 
153     /**
154      * An integration test for client-manager interaction, that will allocate, then frees all
155      * devices.
156      */
testAllocateFreeAll()157     public void testAllocateFreeAll() throws Exception {
158         ITestDevice device = EasyMock.createMock(ITestDevice.class);
159         EasyMock.expect(device.getSerialNumber()).andStubReturn("serial");
160         EasyMock.expect(mMockDeviceManager.forceAllocateDevice("serial")).andReturn(device);
161         mMockDeviceManager.freeDevice(EasyMock.eq(device),
162                 EasyMock.eq(FreeDeviceState.AVAILABLE));
163 
164         EasyMock.replay(mMockDeviceManager, device);
165         mRemoteMgr.connectAnyPort();
166         mRemoteMgr.start();
167         int port = mRemoteMgr.getPort();
168         assertTrue(port != -1);
169         mRemoteClient = RemoteClient.connect(port);
170         mRemoteClient.sendAllocateDevice("serial");
171         mRemoteClient.sendFreeDevice("*");
172         EasyMock.verify(mMockDeviceManager);
173     }
174 
175     /**
176      * Test attempt to free an unknown device
177      */
testFree_unknown()178     public void testFree_unknown() throws Exception {
179         mRemoteMgr.connectAnyPort();
180         mRemoteMgr.start();
181         int port = mRemoteMgr.getPort();
182         assertTrue(port != -1);
183         mRemoteClient = RemoteClient.connect(port);
184         try {
185             mRemoteClient.sendFreeDevice("foo");
186             fail("RemoteException not thrown");
187         } catch (RemoteException e) {
188             // expected
189         }
190     }
191 
192     /**
193      * An integration test for {@link ListDevicesOp}
194      */
testListDevices()195     public void testListDevices() throws Exception {
196         List<DeviceDescriptor> deviceList =
197                 new ArrayList<DeviceDescriptor>(2);
198         deviceList.add(
199             new DeviceDescriptor(
200                 "serial",
201                 false,
202                 DeviceAllocationState.Available,
203                 "tuna",
204                 "toro",
205                 "18",
206                 "JWR67C",
207                 "4")
208             );
209         deviceList.add(
210             new DeviceDescriptor(
211                 "serial2",
212                 false,
213                 DeviceAllocationState.Allocated,
214                 "herring",
215                 "crespo",
216                 "15",
217                 "IMM767",
218                 "5")
219             );
220         EasyMock.expect(mMockDeviceManager.listAllDevices()).andReturn(deviceList);
221         EasyMock.replay(mMockDeviceManager);
222         mRemoteMgr.connectAnyPort();
223         mRemoteMgr.start();
224         int port = mRemoteMgr.getPort();
225         assertTrue(port != -1);
226         mRemoteClient = RemoteClient.connect(port);
227         List<DeviceDescriptor> returnedDevices = mRemoteClient.sendListDevices();
228         assertEquals(2, returnedDevices.size());
229         assertEquals("serial", returnedDevices.get(0).getSerial());
230         assertFalse(returnedDevices.get(0).isStubDevice());
231         assertEquals(DeviceAllocationState.Available, returnedDevices.get(0).getState());
232         assertEquals("tuna", returnedDevices.get(0).getProduct());
233         assertEquals("toro", returnedDevices.get(0).getProductVariant());
234         assertEquals("18", returnedDevices.get(0).getSdkVersion());
235         assertEquals("JWR67C", returnedDevices.get(0).getBuildId());
236         assertEquals("4", returnedDevices.get(0).getBatteryLevel());
237         assertEquals("serial2", returnedDevices.get(1).getSerial());
238         assertFalse(returnedDevices.get(1).isStubDevice());
239         assertEquals(DeviceAllocationState.Allocated, returnedDevices.get(1).getState());
240         assertEquals("herring", returnedDevices.get(1).getProduct());
241         assertEquals("crespo", returnedDevices.get(1).getProductVariant());
242         assertEquals("15", returnedDevices.get(1).getSdkVersion());
243         assertEquals("IMM767", returnedDevices.get(1).getBuildId());
244         assertEquals("5", returnedDevices.get(1).getBatteryLevel());
245         EasyMock.verify(mMockDeviceManager);
246     }
247 
248     /**
249      * An integration test for normal case {@link ExecCommandOp}
250      */
testExecCommand()251     public void testExecCommand() throws Exception {
252         ITestDevice device = EasyMock.createMock(ITestDevice.class);
253         EasyMock.expect(device.getSerialNumber()).andStubReturn("serial");
254         EasyMock.expect(mMockDeviceManager.forceAllocateDevice("serial")).andReturn(device);
255         mMockDeviceManager.freeDevice(EasyMock.eq(device), EasyMock.eq(FreeDeviceState.AVAILABLE));
256         String[] args = new String[] {
257             "instrument"
258         };
259         mMockScheduler.execCommand((IScheduledInvocationListener)EasyMock.anyObject(),
260                 EasyMock.eq(device), EasyMock.aryEq(args));
261 
262         EasyMock.replay(mMockDeviceManager, device, mMockScheduler);
263         mRemoteMgr.connectAnyPort();
264         mRemoteMgr.start();
265         int port = mRemoteMgr.getPort();
266         assertTrue(port != -1);
267         mRemoteClient = RemoteClient.connect(port);
268         mRemoteClient.sendAllocateDevice("serial");
269         mRemoteClient.sendExecCommand("serial", args);
270         mRemoteClient.sendFreeDevice("serial");
271         EasyMock.verify(mMockDeviceManager, mMockScheduler);
272     }
273 
274     /**
275      * An integration test for consecutive executes {@link ExecCommandOp}
276      */
testConsecutiveExecCommand()277     public void testConsecutiveExecCommand() throws Exception {
278         final ITestDevice device = EasyMock.createMock(ITestDevice.class);
279         EasyMock.expect(device.getSerialNumber()).andStubReturn("serial");
280         EasyMock.expect(mMockDeviceManager.forceAllocateDevice("serial")).andReturn(device);
281         mMockDeviceManager.freeDevice(EasyMock.eq(device), EasyMock.eq(FreeDeviceState.AVAILABLE));
282         String[] args = new String[] {
283             "instrument"
284         };
285         mMockScheduler.execCommand((IScheduledInvocationListener)EasyMock.anyObject(),
286                 EasyMock.eq(device), EasyMock.aryEq(args));
287         IAnswer<Object> commandSuccessAnswer = new IAnswer<Object>() {
288             @SuppressWarnings("unchecked")
289             @Override
290             public Object answer() {
291               ExecCommandTracker commandTracker =
292                   (ExecCommandTracker) EasyMock.getCurrentArguments()[0];
293               IInvocationContext nullMeta = new InvocationContext();
294               nullMeta.addAllocatedDevice("device", device);
295               Map<ITestDevice, FreeDeviceState> state = new HashMap<>();
296               state.put(device, FreeDeviceState.UNAVAILABLE);
297               commandTracker.invocationComplete(nullMeta, state);
298               return null;
299             }
300         };
301         EasyMock.expectLastCall().andAnswer(commandSuccessAnswer);
302 
303         mMockScheduler.execCommand((IScheduledInvocationListener)EasyMock.anyObject(),
304             EasyMock.eq(device), EasyMock.aryEq(args));
305         EasyMock.replay(mMockDeviceManager, device, mMockScheduler);
306         mRemoteMgr.connectAnyPort();
307         mRemoteMgr.start();
308         int port = mRemoteMgr.getPort();
309         assertTrue(port != -1);
310         mRemoteClient = RemoteClient.connect(port);
311         mRemoteClient.sendAllocateDevice("serial");
312         // First command succeeds right way.
313         mRemoteClient.sendExecCommand("serial", args);
314         // Second command will be scheduled but will not finish.
315         mRemoteClient.sendExecCommand("serial", args);
316         // Third command will fail since the second command is still executing.
317         try {
318             mRemoteClient.sendExecCommand("serial", args);
319             fail("did not receive RemoteException");
320         } catch (RemoteException e) {
321             // expected
322         }
323         mRemoteClient.sendFreeDevice("serial");
324         EasyMock.verify(mMockDeviceManager, mMockScheduler);
325     }
326 
327     /**
328      * An integration test for case where device was not allocated before {@link ExecCommandOp}
329      */
testExecCommand_noallocate()330     public void testExecCommand_noallocate() throws Exception {
331         mRemoteMgr.connectAnyPort();
332         mRemoteMgr.start();
333         int port = mRemoteMgr.getPort();
334         assertTrue(port != -1);
335         mRemoteClient = RemoteClient.connect(port);
336         try {
337             mRemoteClient.sendExecCommand("serial", new String[] {"instrument"});
338         } catch (RemoteException e) {
339             // expected
340             return;
341         }
342         fail("did not receive RemoteException");
343     }
344 
345     /**
346      * Happy-path test for a handover start
347      */
testHandover()348     public void testHandover() throws Exception {
349         final int port = 88;
350         EasyMock.expect(mMockScheduler.handoverShutdown(port)).andReturn(Boolean.TRUE);
351 
352         EasyMock.replay(mMockScheduler);
353         mRemoteMgr.connectAnyPort();
354         mRemoteMgr.start();
355         int mgrPort = mRemoteMgr.getPort();
356         assertTrue(mgrPort != -1);
357         mRemoteClient = RemoteClient.connect(mgrPort);
358         mRemoteClient.sendStartHandover(port);
359         // disgusting sleep alert! TODO: change to a wait-notify thingy
360         Thread.sleep(100);
361         EasyMock.verify(mMockScheduler);
362     }
363 
364     /**
365      * Basic test for a handover init complete op
366      */
testHandoverInit()367     public void testHandoverInit() throws Exception {
368         // expect
369         mMockScheduler.handoverInitiationComplete();
370 
371         EasyMock.replay(mMockScheduler);
372         mRemoteMgr.connectAnyPort();
373         mRemoteMgr.start();
374         int mgrPort = mRemoteMgr.getPort();
375         assertTrue(mgrPort != -1);
376         mRemoteClient = RemoteClient.connect(mgrPort);
377         mRemoteClient.sendHandoverInitComplete();
378         // disgusting sleep alert! TODO: change to a wait-notify thingy
379         Thread.sleep(100);
380         EasyMock.verify(mMockScheduler);
381     }
382 
383     /**
384      * Test {@link GetLastCommandResultOp} result when device is unknown
385      * @throws Exception
386      */
testGetLastCommandResult_unknownDevice()387     public void testGetLastCommandResult_unknownDevice() throws Exception {
388         ICommandResultHandler mockHandler = EasyMock.createStrictMock(ICommandResultHandler.class);
389         mockHandler.notAllocated();
390         mRemoteMgr.connectAnyPort();
391         mRemoteMgr.start();
392 
393         int mgrPort = mRemoteMgr.getPort();
394         assertTrue(mgrPort != -1);
395         mRemoteClient = RemoteClient.connect(mgrPort);
396         EasyMock.replay(mockHandler);
397 
398         mRemoteClient.sendGetLastCommandResult("foo", mockHandler);
399 
400         EasyMock.verify(mockHandler);
401     }
402 
403     /**
404      * Test {@link GetLastCommandResultOp} result when there is no active command
405      */
testGetLastCommandResult_noActiveCommand()406     public void testGetLastCommandResult_noActiveCommand() throws Exception {
407         ICommandResultHandler mockHandler = EasyMock.createStrictMock(ICommandResultHandler.class);
408         mockHandler.noActiveCommand();
409         ITestDevice device = EasyMock.createMock(ITestDevice.class);
410         EasyMock.expect(device.getSerialNumber()).andStubReturn("serial");
411         EasyMock.expect(mMockDeviceManager.forceAllocateDevice("serial")).andReturn(device);
412         mMockDeviceManager.freeDevice(EasyMock.eq(device), EasyMock.eq(FreeDeviceState.AVAILABLE));
413         EasyMock.replay(mMockDeviceManager, device, mockHandler);
414 
415         mRemoteMgr.connectAnyPort();
416         mRemoteMgr.start();
417         int mgrPort = mRemoteMgr.getPort();
418         assertTrue(mgrPort != -1);
419         mRemoteClient = RemoteClient.connect(mgrPort);
420 
421         mRemoteClient.sendAllocateDevice("serial");
422         mRemoteClient.sendGetLastCommandResult("serial", mockHandler);
423         mRemoteClient.sendFreeDevice("serial");
424 
425         EasyMock.verify(mockHandler, mMockDeviceManager);
426     }
427 
428     /**
429      * Test {@link GetLastCommandResultOp} result when command is executing
430      */
testGetLastCommandResult_executing()431     public void testGetLastCommandResult_executing() throws Exception {
432         ICommandResultHandler mockHandler = EasyMock.createStrictMock(ICommandResultHandler.class);
433         mockHandler.stillRunning();
434         ITestDevice device = EasyMock.createMock(ITestDevice.class);
435         EasyMock.expect(device.getSerialNumber()).andStubReturn("serial");
436         EasyMock.expect(mMockDeviceManager.forceAllocateDevice("serial")).andReturn(device);
437         mMockDeviceManager.freeDevice(EasyMock.eq(device), EasyMock.eq(FreeDeviceState.AVAILABLE));
438         String[] args = new String[] {
439             "instrument"
440         };
441         mMockScheduler.execCommand((IScheduledInvocationListener)EasyMock.anyObject(),
442                 EasyMock.eq(device), EasyMock.aryEq(args));
443 
444         EasyMock.replay(mMockDeviceManager, device, mMockScheduler, mockHandler);
445         mRemoteMgr.connectAnyPort();
446         mRemoteMgr.start();
447         int port = mRemoteMgr.getPort();
448         assertTrue(port != -1);
449         mRemoteClient = RemoteClient.connect(port);
450         mRemoteClient.sendAllocateDevice("serial");
451         mRemoteClient.sendExecCommand("serial", args);
452         mRemoteClient.sendGetLastCommandResult("serial", mockHandler);
453         mRemoteClient.sendFreeDevice("serial");
454         EasyMock.verify(mMockDeviceManager, mockHandler);
455     }
456 
457     /**
458      * Test {@link GetLastCommandResultOp} result when commmand fails due to a not available device.
459      */
460     @SuppressWarnings("unchecked")
testGetLastCommandResult_notAvail()461     public void testGetLastCommandResult_notAvail() throws Exception {
462         ICommandResultHandler mockHandler = EasyMock.createStrictMock(ICommandResultHandler.class);
463         mockHandler.failure((String)EasyMock.anyObject(), EasyMock.eq(FreeDeviceState.UNAVAILABLE),
464                 (Map<String, String>)EasyMock.anyObject());
465         final ITestDevice device = EasyMock.createMock(ITestDevice.class);
466         EasyMock.expect(device.getSerialNumber()).andStubReturn("serial");
467         EasyMock.expect(mMockDeviceManager.forceAllocateDevice("serial")).andReturn(device);
468         // TODO: change to not available
469         mMockDeviceManager.freeDevice(EasyMock.eq(device), EasyMock.eq(FreeDeviceState.AVAILABLE));
470         String[] args = new String[] {
471             "instrument"
472         };
473         mMockScheduler.execCommand((IScheduledInvocationListener)EasyMock.anyObject(),
474                 EasyMock.eq(device), EasyMock.aryEq(args));
475         IAnswer<Void> invErrorAnswer = new IAnswer<Void>() {
476             @Override
477             public Void answer() throws Throwable {
478                 IScheduledInvocationListener listener =
479                         (IScheduledInvocationListener)EasyMock.getCurrentArguments()[0];
480                 IInvocationContext nullMeta = new InvocationContext();
481                 nullMeta.addAllocatedDevice("device", device);
482                 nullMeta.addDeviceBuildInfo("device", new BuildInfo());
483                 listener.invocationStarted(nullMeta);
484                 listener.invocationFailed(new DeviceNotAvailableException());
485                 listener.invocationEnded(1);
486                 Map<ITestDevice, FreeDeviceState> state = new HashMap<>();
487                 state.put(device, FreeDeviceState.UNAVAILABLE);
488                 listener.invocationComplete(nullMeta, state);
489                 return null;
490             }
491         };
492         EasyMock.expectLastCall().andAnswer(invErrorAnswer);
493 
494         EasyMock.replay(mMockDeviceManager, device, mMockScheduler, mockHandler);
495         mRemoteMgr.connectAnyPort();
496         mRemoteMgr.start();
497         int port = mRemoteMgr.getPort();
498         assertTrue(port != -1);
499         mRemoteClient = RemoteClient.connect(port);
500         mRemoteClient.sendAllocateDevice("serial");
501         mRemoteClient.sendExecCommand("serial", args);
502         mRemoteClient.sendGetLastCommandResult("serial", mockHandler);
503         mRemoteClient.sendFreeDevice("serial");
504         EasyMock.verify(mMockDeviceManager, mockHandler, mMockScheduler);
505     }
506 }
507