View Javadoc
1   package com.simpligility.maven.plugins.android;
2   
3   import static org.easymock.EasyMock.anyObject;
4   import static org.easymock.EasyMock.expect;
5   import static org.easymock.EasyMock.isNull;
6   import static org.easymock.EasyMock.replay;
7   import static org.easymock.EasyMock.verify;
8   import static org.junit.Assert.fail;
9   import static org.powermock.api.easymock.PowerMock.createMock;
10  import static org.powermock.api.easymock.PowerMock.mockStatic;
11  
12  import java.io.IOException;
13  import java.util.List;
14  
15  import org.apache.maven.plugin.MojoExecutionException;
16  import org.apache.maven.plugin.MojoFailureException;
17  import org.junit.Before;
18  import org.junit.Ignore;
19  import org.junit.Test;
20  import org.junit.runner.RunWith;
21  import org.powermock.api.easymock.PowerMock;
22  import org.powermock.core.classloader.annotations.PrepareForTest;
23  import org.powermock.modules.junit4.PowerMockRunner;
24  
25  import com.android.ddmlib.AdbCommandRejectedException;
26  import com.android.ddmlib.AndroidDebugBridge;
27  import com.android.ddmlib.IDevice;
28  import com.android.ddmlib.ShellCommandUnresponsiveException;
29  import com.android.ddmlib.TimeoutException;
30  
31  @RunWith( PowerMockRunner.class )
32  @PrepareForTest(
33  { AndroidDebugBridge.class, CommandExecutor.Factory.class } )
34  @Ignore("Does not work anymore with new sdk")
35  public class AbstractEmulatorMojoTest
36  {
37      private static final String AVD_NAME = "emulator";
38      private static final long DEFAULT_TIMEOUT = 500;
39      private AbstractEmulatorMojoToTest abstractEmulatorMojo;
40      private CommandExecutor mockExecutor;
41      private AndroidDebugBridge mockAndroidDebugBridge;
42  
43      @Before
44      public void setUp() throws Exception
45      {
46          mockExecutor = PowerMock.createNiceMock( CommandExecutor.class );
47          mockExecutor.executeCommand( anyObject( String.class ), isNull( List.class ) );
48          PowerMock.replay( mockExecutor );
49  
50          mockStatic( CommandExecutor.Factory.class );
51          expect( CommandExecutor.Factory.createDefaultCommmandExecutor() ).andReturn( mockExecutor );
52          PowerMock.replay( CommandExecutor.Factory.class );
53  
54          mockAndroidDebugBridge = createMock( AndroidDebugBridge.class );
55  
56          abstractEmulatorMojo = new AbstractEmulatorMojoToTest();
57      }
58  
59      @Test
60      public void testStartAndroidEmulatorWithTimeoutToConnect() throws MojoExecutionException, ExecutionException
61      {
62          boolean onlineAtSecondTry = false;
63          int extraBootStatusPollCycles = -1;//ignored
64          abstractEmulatorMojo.setWait( DEFAULT_TIMEOUT );
65  
66          IDevice emulatorDevice = withEmulatorDevice( onlineAtSecondTry, extraBootStatusPollCycles );
67  
68          withConnectedDebugBridge( emulatorDevice );
69  
70          try
71          {
72              abstractEmulatorMojo.startAndroidEmulator();
73              fail();
74          }
75          catch ( MojoExecutionException e )
76          {
77              verify( mockExecutor );
78          }
79      }
80  
81      @Test
82      public void testStartAndroidEmulatorAlreadyBooted() throws MojoExecutionException, ExecutionException
83      {
84          boolean onlineAtSecondTry = true;
85          int extraBootStatusPollCycles = 0;
86          abstractEmulatorMojo.setWait( DEFAULT_TIMEOUT );
87  
88          IDevice emulatorDevice = withEmulatorDevice( onlineAtSecondTry, extraBootStatusPollCycles );
89          withConnectedDebugBridge( emulatorDevice );
90  
91          abstractEmulatorMojo.startAndroidEmulator();
92  
93          verify( mockExecutor );
94      }
95  
96      @Test
97      public void testStartAndroidEmulatorWithOngoingBoot() throws MojoExecutionException, ExecutionException
98      {
99          boolean onlineAtSecondTry = true;
100         int extraBootStatusPollCycles = 1;
101         abstractEmulatorMojo.setWait( extraBootStatusPollCycles * 5000 + 500 );
102 
103         IDevice emulatorDevice = withEmulatorDevice( onlineAtSecondTry, extraBootStatusPollCycles );
104         withConnectedDebugBridge( emulatorDevice );
105 
106         abstractEmulatorMojo.startAndroidEmulator();
107 
108         verify( mockExecutor );
109     }
110 
111     @Test
112     public void testStartAndroidEmulatorWithBootTimeout() throws MojoExecutionException, ExecutionException
113     {
114         boolean onlineAtSecondTry = true;
115         int extraBootStatusPollCycles = -1;
116         abstractEmulatorMojo.setWait( DEFAULT_TIMEOUT );
117 
118         IDevice emulatorDevice = withEmulatorDevice( onlineAtSecondTry, extraBootStatusPollCycles );
119         withConnectedDebugBridge( emulatorDevice );
120 
121         try
122         {
123             abstractEmulatorMojo.startAndroidEmulator();
124             fail();
125         }
126         catch ( MojoExecutionException e )
127         {
128             verify( mockExecutor );
129         }
130     }
131 
132     /**
133      * @param onlineAtSecondTry
134      * @param extraBootStatusPollCycles < 0 to simulate 'stuck in boot animation'
135      * @return
136      */
137     private IDevice withEmulatorDevice( boolean onlineAtSecondTry, int extraBootStatusPollCycles )
138     {
139         IDevice emulatorDevice = createMock( IDevice.class );
140         expect( emulatorDevice.getAvdName() ).andReturn( AVD_NAME ).atLeastOnce();
141         expect( emulatorDevice.isEmulator() ).andReturn( true ).atLeastOnce();
142         if ( onlineAtSecondTry )
143         {
144             try
145             {
146                 expect( emulatorDevice.isOnline() ).andReturn( false ).andReturn( true );
147 
148                 if ( extraBootStatusPollCycles < 0 )
149                 {
150                     //Simulate 'stuck in boot animation'
151                     expect( emulatorDevice.getPropertySync( "dev.bootcomplete" ) )
152                             .andReturn( null ).atLeastOnce();
153                     expect( emulatorDevice.getPropertySync( "sys.boot_completed" ) )
154                             .andReturn( null ).atLeastOnce();
155                     expect( emulatorDevice.getPropertySync( "init.svc.bootanim" ) )
156                             .andReturn( null ).once()
157                             .andReturn( "running" ).atLeastOnce(); //never changes to "stopped"
158                 }
159                 else if ( extraBootStatusPollCycles == 0 )
160                 {
161                     //Simulate 'already booted'
162                     expect( emulatorDevice.getPropertySync( "dev.bootcomplete" ) )
163                             .andReturn( "1" ).once(); //to be cached
164                     expect( emulatorDevice.getPropertySync( "sys.boot_completed" ) )
165                             .andReturn( "1" ).once(); //to be cached
166                     expect( emulatorDevice.getPropertySync( "init.svc.bootanim" ) )
167                             .andReturn( "stopped" ).once(); //to be cached
168                 }
169                 else if ( extraBootStatusPollCycles == 1 )
170                 {
171                     //Simulate 'almost booted (1 extra poll)'
172                     expect( emulatorDevice.getPropertySync( "dev.bootcomplete" ) )
173                             .andReturn( null ).once()
174                             .andReturn( "1" ).once(); //to be cached
175                     expect( emulatorDevice.getPropertySync( "sys.boot_completed" ) )
176                             .andReturn( null ).once()
177                             .andReturn( "1" ).once(); //to be cached
178                     expect( emulatorDevice.getPropertySync( "init.svc.bootanim" ) )
179                             .andReturn( "running" ).once()
180                             .andReturn( "stopped" ).once(); //to be cached
181                 }
182                 else if( extraBootStatusPollCycles >=3 )
183                 {
184                     //Simulate 'almost booted (>=3 extra polls)'
185                     expect( emulatorDevice.getPropertySync( "dev.bootcomplete" ) )
186                             .andReturn( null ).times( extraBootStatusPollCycles - 1 )
187                             .andReturn( "1" ).once(); //to be cached
188                     expect( emulatorDevice.getPropertySync( "sys.boot_completed" ) )
189                             .andReturn( null ).times( extraBootStatusPollCycles - 1 )
190                             .andReturn( "1" ).once(); //to be cached
191                     expect( emulatorDevice.getPropertySync( "init.svc.bootanim" ) )
192                             .andReturn( null ).times( extraBootStatusPollCycles / 2 )
193                             .andReturn( "running" ).times( extraBootStatusPollCycles / 2 + extraBootStatusPollCycles % 2 )
194                             .andReturn( "stopped" ).once(); //to be cached
195                 }
196                 else if( extraBootStatusPollCycles >=2 )
197                 {
198                     //Simulate 'almost booted (>=2 extra polls)'
199                     expect( emulatorDevice.getPropertySync( "dev.bootcomplete" ) )
200                             .andReturn( null ).times( extraBootStatusPollCycles - 1 )
201                             .andReturn( "1" ).once(); //to be cached
202                     expect( emulatorDevice.getPropertySync( "sys.boot_completed" ) )
203                             .andReturn( null ).times( extraBootStatusPollCycles - 1 )
204                             .andReturn( "1" ).once(); //to be cached
205                     expect( emulatorDevice.getPropertySync( "init.svc.bootanim" ) )
206                             .andReturn( "running" ).times( extraBootStatusPollCycles -1 )
207                             .andReturn( "stopped" ).once(); //to be cached
208                 }
209             }
210             catch ( TimeoutException e)
211             {
212                 throw new RuntimeException( "Unexpected checked exception during mock setup", e );
213             }
214             catch ( AdbCommandRejectedException e)
215             {
216                 throw new RuntimeException( "Unexpected checked exception during mock setup", e );
217             }
218             catch ( ShellCommandUnresponsiveException e)
219             {
220                 throw new RuntimeException( "Unexpected checked exception during mock setup", e );
221             }
222             catch ( IOException e )
223             {
224                 throw new RuntimeException( "Unexpected checked exception during mock setup", e );
225             }
226         }
227         else
228         {
229             expect( emulatorDevice.isOnline() ).andReturn( false ).atLeastOnce();
230         }
231         replay( emulatorDevice );
232         return emulatorDevice;
233     }
234 
235     private void withConnectedDebugBridge( IDevice emulatorDevice )
236     {
237         expect( mockAndroidDebugBridge.isConnected() ).andReturn( true );
238         expect( mockAndroidDebugBridge.hasInitialDeviceList() ).andReturn( true );
239         expect( mockAndroidDebugBridge.getDevices() ).andReturn( new IDevice[ 0 ] ).andReturn( new IDevice[]
240         { emulatorDevice } ).atLeastOnce();
241         replay( mockAndroidDebugBridge );
242     }
243 
244     private class AbstractEmulatorMojoToTest extends AbstractEmulatorMojo
245     {
246         private long wait = DEFAULT_TIMEOUT;
247 
248         public long getWait()
249         {
250             return wait;
251         }
252 
253         public void setWait( long wait )
254         {
255             this.wait = wait;
256         }
257 
258         @Override
259         protected AndroidSdk getAndroidSdk()
260         {
261             return new SdkTestSupport().getSdk_with_platform_default();
262         }
263 
264         @Override
265         public void execute() throws MojoExecutionException, MojoFailureException
266         {
267         }
268 
269         @Override
270         protected AndroidDebugBridge initAndroidDebugBridge() throws MojoExecutionException
271         {
272             return mockAndroidDebugBridge;
273         }
274 
275         @Override
276         String determineAvd()
277         {
278             return AVD_NAME;
279         }
280 
281         @Override
282         String determineWait()
283         {
284             return String.valueOf( wait );
285         }
286     }
287 
288 }