/* * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of * the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright (c) 2014 Digi International Inc., All Rights Reserved. */ package com.digi.android.wva.test; import android.app.Activity; import android.app.Instrumentation.ActivityMonitor; import android.test.ActivityInstrumentationTestCase2; import android.util.Log; import com.actionbarsherlock.view.MenuItem; import com.digi.addp.AddpClient; import com.digi.addp.AddpDevice; import com.digi.android.wva.DashboardActivity; import com.digi.android.wva.DeviceListActivity; import com.digi.android.wva.R; import com.digi.android.wva.SettingsActivity; import com.digi.android.wva.WvaApplication; import com.digi.android.wva.adapters.EndpointsAdapter; import com.digi.android.wva.adapters.LogAdapter; import com.digi.android.wva.adapters.VariableAdapter; import com.digi.android.wva.fragments.DeviceDiscoveryFragment; import com.digi.android.wva.util.NetworkUtils; import com.digi.android.wva.util.RefreshManager; import com.digi.android.wva.util.VehicleDataList; import java.net.Inet4Address; import java.util.ArrayList; import java.util.Hashtable; import java.util.List; import java.util.Map; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; public class DeviceListActivityTest extends ActivityInstrumentationTestCase2<DeviceListActivity> { private DeviceListActivity mActivity; private VariableAdapter mAdapter; private AddpClient client; private final List<AddpDevice> devices; public DeviceListActivityTest() throws Exception { super(DeviceListActivity.class); String[] mockNames = new String[] {"Mock Device 1", "Mock Device 2", "Mock Device 3", "Mock Device 4"}; String[] mockIps = new String[] {"192.168.1.1", "192.168.2.1", "192.168.3.1", "192.168.4.1"}; String[] mockDevIds = new String[] {null, null, null, null}; // Set up mock devices to be returned in device discovery. devices = new ArrayList<AddpDevice>(); for (int i = 0; i < mockNames.length; i++) { AddpDevice dev = mock(AddpDevice.class); when(dev.getDeviceID()).thenReturn(mockDevIds[i]); when(dev.getHardwareName()).thenReturn(mockNames[i]); when(dev.getIPAddress()).thenReturn(Inet4Address.getByName(mockIps[i])); devices.add(dev); } } @Override protected void setUp() throws Exception { super.setUp(); setActivityInitialTouchMode(false); mActivity = getActivity(); mAdapter = VariableAdapter.getInstance(); // Mock the ADDP client, mocking all the methods called on it // and its returned objects so that we use our mock AddpDevice objects // added to 'devices'. client = mock(AddpClient.class); when(client.searchForDevices()).thenReturn(true); ((WvaApplication)getActivity().getApplication()).setAddpClient(client); Map<String, AddpDevice> devMap = new Hashtable<String, AddpDevice>(); for (AddpDevice d : devices) { // The actual getDevices return value maps MAC address to device, but // we just need a String->AddpDevice mapping here. devMap.put(d.getIPAddress().getHostName(), d); } when(client.getDevices()).thenReturn(devMap); } @Override protected void tearDown() throws Exception { super.tearDown(); // super doesn't destroy (i.e. finish) activity getActivity().finish(); } private void failWithoutNetwork() { if (!NetworkUtils.shouldBeAllowedToConnect(getActivity())) { fail("Not connected to Wi-Fi, so why bother testing?"); } } public void testActivityOkay() { failWithoutNetwork(); assertNotNull("Activity is null!", mActivity); assertNotNull("VariableAdapter not initialized", mAdapter); } public void testExistSingletons() { failWithoutNetwork(); assertNotNull("Log adapter uninitialized", LogAdapter.getInstance()); assertNotNull("Data list uninitialized", VehicleDataList.getInstance()); assertNotNull("Variable adapter uninitialized", VariableAdapter.getInstance()); assertNotNull("Endpoints adapter uninitialized", EndpointsAdapter.getInstance()); } public void testPressRefresh() { failWithoutNetwork(); WvaApplication app = (WvaApplication) getActivity().getApplication(); // Get handle to device list fragment final DeviceDiscoveryFragment f = (DeviceDiscoveryFragment) mActivity .getSupportFragmentManager() .findFragmentById(R.id.device_fragment); // Check that the fragment is there (why wouldn't it be?) assertNotNull("No R.id.device_fragment", f); // Make sure our mock ADDP client is being used. // It seems like the lifecycle of native fragments vs. support fragments // (i.e. fragments on 3.0/4.0+ vs. lower versions of Android) are // different... fragments are not created in these test cases until // after setUp() code has completed? // So we set the AddpClient for certain, here. if (app.getAddpClient() != client) app.setAddpClient(client); RefreshManager rm = f.getRefreshManager(); // First, check the refresh manager exists (as it should) assertNotNull("Null refresh manager on fragment", rm); // Hit "Refresh" MenuItem refresher = f.getRefreshItem(); while (refresher == null) { try { Thread.sleep(100); } catch (InterruptedException ignored) { } refresher = f.getRefreshItem(); } final MenuItem theItem = refresher; // Execute onOptionsItemSelected from the main thread, so that // it can do what it normally does. app.getHandler().post(new Runnable() { public void run() { f.onOptionsItemSelected(theItem); } }); // Sleep long enough for the async task (wherein the AddpClient search // will return immediately, because we mocked the AddpClient) to // complete and set the refresh manager back to not refreshing. try { Thread.sleep(3000); } catch (InterruptedException ignored) {} assertTrue("Refresh manager is still refreshing. This may be expected, if the test device is slow.", rm.isNotRefreshing()); verify(client).searchForDevices(); verify(client).getDevices(); } /** * Only exists for testing in-development app. Once the device discovery * and connection is all in place, manual device-info activity launch * will be removed. */ public void testManualLaunch() { failWithoutNetwork(); // ala http://stackoverflow.com/q/5209154 ActivityMonitor am = getInstrumentation().addMonitor( DashboardActivity.class.getName(), null, false); // send menu item invocation getInstrumentation().invokeMenuActionSync(mActivity, R.id.manual_view, 0); Log.d("DeviceListActivityTest", "menu action invoked"); // Check that the dashboard activity was launched // note: waitForMonitorWithTimeout documentation is incorrect... // docs says timeout is in seconds, it is actually milliseconds Activity activity = getInstrumentation().waitForMonitorWithTimeout(am, 1000); assertTrue("Dashboard activity not launched", getInstrumentation().checkMonitorHit(am, 1)); Log.d("DeviceListActivityTest", "Finishing dashboard activity"); // finish dashboard activity if (activity != null) activity.finish(); try { // Seems like the code below gets called before onDestroy changes // propagate through the system if no delay like this is introduced. Thread.sleep(500); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * Check that hitting 'Settings' launches the Settings activity */ public void testSettingsLaunch() { ActivityMonitor am = getInstrumentation().addMonitor( SettingsActivity.class.getName(), null, false); getInstrumentation().invokeMenuActionSync(mActivity, R.id.action_settings, 0); Activity sa = getInstrumentation().waitForMonitorWithTimeout(am, 1000); assertTrue("Settings activity not launched", getInstrumentation().checkMonitorHit(am, 1)); if (sa != null) sa.finish(); } }