diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/endtoendtest/CreateAndSendTrackTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/endtoendtest/CreateAndSendTrackTest.java new file mode 100644 index 000000000..41c4037cb --- /dev/null +++ b/MyTracksTest/src/com/google/android/apps/mytracks/endtoendtest/CreateAndSendTrackTest.java @@ -0,0 +1,183 @@ +/* + * Copyright 2012 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.android.apps.mytracks.endtoendtest; + +import com.google.android.apps.mytracks.TrackListActivity; +import com.google.android.maps.mytracks.R; + +import android.app.Instrumentation; +import android.test.ActivityInstrumentationTestCase2; +import android.view.KeyEvent; +import android.widget.CheckBox; + +import java.util.ArrayList; + +/** + * Tests creating a track with markers, and editing and sending send a track. + * + * @author Youtao Liu + */ +public class CreateAndSendTrackTest extends ActivityInstrumentationTestCase2 { + + private static final String WAYPOINT_NAME = "testWaypoint"; + private static final String STATISTICS_NAME = "testStatistics"; + private Instrumentation instrumentation; + private TrackListActivity activityMyTracks; + + public CreateAndSendTrackTest() { + super(TrackListActivity.class); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + instrumentation = getInstrumentation(); + activityMyTracks = getActivity(); + EndToEndTestUtils.setupForAllTest(instrumentation, activityMyTracks); + } + + /** + * Creates a track with markers and the setting to send to google. + */ + public void testCreateAndSendTrack() { + // Create a track at first. + EndToEndTestUtils.createSimpleTrack(1); + instrumentation.waitForIdleSync(); + sendKeys(KeyEvent.KEYCODE_MENU); + EndToEndTestUtils.findMenuItem(activityMyTracks.getString(R.string.menu_send_google), true, false); + EndToEndTestUtils.SOLO.waitForText(activityMyTracks.getString(R.string.send_google_title)); + EndToEndTestUtils.rotateCurrentActivity(); + instrumentation.waitForIdleSync(); + + ArrayList checkBoxs = EndToEndTestUtils.SOLO.getCurrentCheckBoxes(); + for (int i = 0; i < checkBoxs.size(); i++) { + if (checkBoxs.get(i).isChecked()) { + EndToEndTestUtils.SOLO.clickOnCheckBox(i); + } + } + + if (checkBoxs.size() < 3) { + EndToEndTestUtils.SOLO.scrollDown(); + checkBoxs = EndToEndTestUtils.SOLO.getCurrentCheckBoxes(); + for (int i = 0; i < checkBoxs.size(); i++) { + if (checkBoxs.get(i).isChecked()) { + EndToEndTestUtils.SOLO.clickOnCheckBox(i); + } + } + } + + instrumentation.waitForIdleSync(); + EndToEndTestUtils.SOLO.clickOnText(activityMyTracks.getString(R.string.send_google_send_now)); + assertTrue(EndToEndTestUtils.SOLO.waitForText(activityMyTracks + .getString(R.string.send_google_no_service_selected))); + // Stop here for do not really send. + } + + /** + * Tests editing a track. + */ + public void testEditTrack() { + EndToEndTestUtils.createSimpleTrack(0); + instrumentation.waitForIdleSync(); + sendKeys(KeyEvent.KEYCODE_MENU); + EndToEndTestUtils.findMenuItem(activityMyTracks.getString(R.string.menu_edit), true, false); + + String newTrackName = EndToEndTestUtils.TRACK_NAME_PREFIX + "_new" + System.currentTimeMillis(); + String newType = "type" + newTrackName; + String newDesc = "desc" + newTrackName; + + instrumentation.waitForIdleSync(); + EndToEndTestUtils.rotateAllActivities(); + sendKeys(KeyEvent.KEYCODE_DEL); + EndToEndTestUtils.SOLO.enterText(0, newTrackName); + sendKeys(KeyEvent.KEYCODE_TAB); + EndToEndTestUtils.SOLO.enterText(1, newType); + sendKeys(KeyEvent.KEYCODE_TAB); + EndToEndTestUtils.SOLO.enterText(2, newDesc); + + EndToEndTestUtils.SOLO.clickOnButton(activityMyTracks.getString(R.string.generic_save)); + instrumentation.waitForIdleSync(); + // Go back to track list. + EndToEndTestUtils.SOLO.goBack(); + + assertTrue(EndToEndTestUtils.SOLO.searchText(newTrackName)); + assertTrue(EndToEndTestUtils.SOLO.searchText(newDesc)); + } + + /** + * Creates one track with a two locations, a way point and a statistics point. + */ + public void testCreateTrackWithMarkers() { + EndToEndTestUtils.SOLO.sendKey(KeyEvent.KEYCODE_MENU); + EndToEndTestUtils.findMenuItem(activityMyTracks.getString(R.string.menu_delete_all), true, false); + EndToEndTestUtils.SOLO.clickOnButton(activityMyTracks.getString(R.string.generic_ok)); + instrumentation.waitForIdleSync(); + + EndToEndTestUtils.startRecording(); + instrumentation.waitForIdleSync(); + EndToEndTestUtils.sendGps(2); + createWaypointAndStatistics(); + EndToEndTestUtils.sendGps(2); + // Back to tracks list. + EndToEndTestUtils.SOLO.goBack(); + instrumentation.waitForIdleSync(); + EndToEndTestUtils.rotateAllActivities(); + EndToEndTestUtils.stopRecording(false); + EndToEndTestUtils.TRACK_NAME = EndToEndTestUtils.TRACK_NAME_PREFIX + System.currentTimeMillis(); + EndToEndTestUtils.SOLO.enterText(0, EndToEndTestUtils.TRACK_NAME); + EndToEndTestUtils.SOLO.clickOnButton(activityMyTracks.getString(R.string.generic_save)); + + instrumentation.waitForIdleSync(); + // Check the new track + assertTrue(EndToEndTestUtils.SOLO.waitForText(EndToEndTestUtils.TRACK_NAME, 1, 5000, true, false)); + } + + /** + * Creates a way point and a statistics during track recording. + */ + private void createWaypointAndStatistics() { + sendKeys(KeyEvent.KEYCODE_MENU); + EndToEndTestUtils.findMenuItem(activityMyTracks.getString(R.string.menu_markers), true, false); + + assertTrue(EndToEndTestUtils.SOLO.waitForText(activityMyTracks.getString(R.string.marker_list_empty_message))); + + sendKeys(KeyEvent.KEYCODE_MENU); + EndToEndTestUtils.findMenuItem(activityMyTracks.getString(R.string.menu_insert_marker), true, true); + EndToEndTestUtils.SOLO.clickOnText(activityMyTracks.getString(R.string.marker_edit_type_waypoint)); + EndToEndTestUtils.rotateAllActivities(); + EndToEndTestUtils.SOLO.enterText(0, WAYPOINT_NAME); + EndToEndTestUtils.SOLO.clickOnButton(activityMyTracks.getString(R.string.marker_edit_add)); + assertTrue(EndToEndTestUtils.SOLO.searchText(WAYPOINT_NAME)); + + sendKeys(KeyEvent.KEYCODE_MENU); + EndToEndTestUtils.findMenuItem(activityMyTracks.getString(R.string.menu_insert_marker), true, true); + EndToEndTestUtils.SOLO.clickOnText(activityMyTracks.getString(R.string.marker_edit_type_statistics)); + EndToEndTestUtils.rotateAllActivities(); + EndToEndTestUtils.SOLO.enterText(0, STATISTICS_NAME); + EndToEndTestUtils.SOLO.clickOnButton(activityMyTracks.getString(R.string.marker_edit_add)); + instrumentation.waitForIdleSync(); + assertTrue(EndToEndTestUtils.SOLO.searchText(STATISTICS_NAME)); + + EndToEndTestUtils.SOLO.goBack(); + } + + @Override + protected void tearDown() throws Exception { + EndToEndTestUtils.SOLO.finishOpenedActivities(); + super.tearDown(); + } + +} diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/endtoendtest/DeleteTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/endtoendtest/DeleteTest.java new file mode 100644 index 000000000..b91a360ff --- /dev/null +++ b/MyTracksTest/src/com/google/android/apps/mytracks/endtoendtest/DeleteTest.java @@ -0,0 +1,100 @@ +/* + * Copyright 2012 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.android.apps.mytracks.endtoendtest; + +import com.google.android.apps.mytracks.TrackListActivity; +import com.google.android.maps.mytracks.R; + +import android.app.Instrumentation; +import android.test.ActivityInstrumentationTestCase2; +import android.view.KeyEvent; +import android.widget.ListView; + +import java.util.ArrayList; + +/** + * Tests the delete of MyTracks. + * + * @author Youtao Liu + */ +public class DeleteTest extends ActivityInstrumentationTestCase2 { + + private Instrumentation instrumentation; + private TrackListActivity activityMyTracks; + + public DeleteTest() { + super(TrackListActivity.class); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + instrumentation = getInstrumentation(); + activityMyTracks = getActivity(); + EndToEndTestUtils.setupForAllTest(instrumentation, activityMyTracks); + } + + /** + * Deletes all tracks. + */ + public void testDeleteAllTracks() { + EndToEndTestUtils.createSimpleTrack(0); + EndToEndTestUtils.SOLO.goBack(); + instrumentation.waitForIdleSync(); + // There is at least one track. + ArrayList trackListView = EndToEndTestUtils.SOLO.getCurrentListViews(); + assertTrue(trackListView.size() > 0); + assertTrue(trackListView.get(0).getCount() > 0); + + EndToEndTestUtils.SOLO.sendKey(KeyEvent.KEYCODE_MENU); + EndToEndTestUtils.findMenuItem(activityMyTracks.getString(R.string.menu_delete_all), true, + false); + instrumentation.waitForIdleSync(); + EndToEndTestUtils.rotateAllActivities(); + EndToEndTestUtils.SOLO.clickOnButton(activityMyTracks.getString(R.string.generic_ok)); + instrumentation.waitForIdleSync(); + // There is no track now. + trackListView = EndToEndTestUtils.SOLO.getCurrentListViews(); + assertEquals(0, trackListView.get(0).getCount()); + } + + /** + * Deletes only one track. + */ + public void testDeleteSingleTrack() { + EndToEndTestUtils.createSimpleTrack(0); + EndToEndTestUtils.SOLO.goBack(); + // Get the number of track( or tracks) + ArrayList trackListView = EndToEndTestUtils.SOLO.getCurrentListViews(); + int trackNumberOld = trackListView.get(0).getCount(); + + EndToEndTestUtils.SOLO.clickLongOnText(EndToEndTestUtils.TRACK_NAME); + EndToEndTestUtils.findMenuItem(activityMyTracks.getString(R.string.menu_delete), true, true); + EndToEndTestUtils.SOLO.clickLongOnText(activityMyTracks.getString(R.string.generic_ok)); + instrumentation.waitForIdleSync(); + trackListView = EndToEndTestUtils.SOLO.getCurrentListViews(); + int trackNumberNew = trackListView.get(0).getCount(); + assertEquals(trackNumberOld - 1, trackNumberNew); + + } + + @Override + protected void tearDown() throws Exception { + EndToEndTestUtils.SOLO.finishOpenedActivities(); + super.tearDown(); + } + +} diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/endtoendtest/EndToEndTestUtils.java b/MyTracksTest/src/com/google/android/apps/mytracks/endtoendtest/EndToEndTestUtils.java new file mode 100644 index 000000000..4750d7df4 --- /dev/null +++ b/MyTracksTest/src/com/google/android/apps/mytracks/endtoendtest/EndToEndTestUtils.java @@ -0,0 +1,362 @@ +/* + * Copyright 2012 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.android.apps.mytracks.endtoendtest; + +import com.google.android.apps.mytracks.TrackListActivity; +import com.google.android.apps.mytracks.util.FileUtils; +import com.google.android.maps.mytracks.R; +import com.jayway.android.robotium.solo.Solo; + +import android.app.Activity; +import android.app.Instrumentation; +import android.content.res.Configuration; +import android.view.KeyEvent; +import android.widget.Button; + +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; +import java.io.PrintStream; +import java.net.Socket; +import java.net.UnknownHostException; +import java.util.ArrayList; + +/** + * Provides utilities to smoke test. + * + * @author Youtao Liu + */ +public class EndToEndTestUtils { + private static final String ANDROID_LOCAL_IP = "10.0.2.2"; + // usually 5554. + private static final int ANDROID_LOCAL_PORT = 5554; + + private static final int ORIENTATION_PORTRAIT = 1; + private static final int ORIENTATION_LANDSCAPE = 0; + // Pause 200ms between each send. + static int PAUSE = 200; + private static final float START_LONGITUDE = 51; + private static final float START_LATITUDE = -1.3f; + private static final float DELTA_LONGITUDE = 0.0005f; + private static final float DELTA_LADITUDE = 0.0005f; + + static final String TRACK_NAME_PREFIX = "testTrackName"; + static final String GPX = "gpx"; + static final String KML = "kml"; + static final String CSV = "csv"; + static final String TCX = "tcx"; + static final String MENU_MORE = "More"; + static String TRACK_NAME; + + static Solo SOLO; + static Instrumentation INSTRUMENTATION; + static TrackListActivity ACTIVITYMYTRACKS; + // Check whether the UI has an action bar which is related with the version of + // Android OS. + static boolean HAS_ACTIONBAR = false; + static boolean CHECKED_FIRSTLAUNCH = false; + + private EndToEndTestUtils() {} + + /** + * Sends Gps data to emulator. + * + * @param number send times + */ + public static void sendGps(int number) { + if (number < 1) { return; } + PrintStream out = null; + Socket socket = null; + try { + socket = new Socket(ANDROID_LOCAL_IP, ANDROID_LOCAL_PORT); + out = new PrintStream(socket.getOutputStream()); + float longitude = START_LONGITUDE; + float latitude = START_LATITUDE; + for (int i = 0; i < number; i++) { + Thread.sleep(PAUSE); + out.println("geo fix " + latitude + " " + longitude); + longitude += DELTA_LONGITUDE; + latitude += DELTA_LADITUDE; + } + } catch (UnknownHostException e) { + System.exit(-1); + } catch (IOException e) { + System.exit(-1); + } catch (InterruptedException e) { + System.exit(-1); + } finally { + if (out != null) { + out.close(); + } + } + } + + /** + * A setup for all end-to-end tests. + * + * @param instrumentation the instrumentation is used for test + * @param activityMyTracks the startup activity + */ + static void setupForAllTest(Instrumentation instrumentation, TrackListActivity activityMyTracks) { + EndToEndTestUtils.INSTRUMENTATION = instrumentation; + EndToEndTestUtils.ACTIVITYMYTRACKS = activityMyTracks; + EndToEndTestUtils.SOLO = new Solo(EndToEndTestUtils.INSTRUMENTATION, + EndToEndTestUtils.ACTIVITYMYTRACKS); + // Check if open MyTracks first time after install. If so, there would be a + // welcome view with accept buttons. And makes sure only check once. + if (!EndToEndTestUtils.CHECKED_FIRSTLAUNCH) { + if ((EndToEndTestUtils.getButtonOnScreen(EndToEndTestUtils.ACTIVITYMYTRACKS + .getString(R.string.eula_accept)) != null)) { + EndToEndTestUtils.verifyFirstLaunch(); + } + + EndToEndTestUtils.CHECKED_FIRSTLAUNCH = true; + EndToEndTestUtils.setHasActionBar(); + } + } + + /** + * Rotates the given activity. + * + * @param activity a given activity + */ + static void rotateActivity(Activity activity) { + activity + .setRequestedOrientation(activity.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT ? ORIENTATION_LANDSCAPE + : ORIENTATION_PORTRAIT); + } + + /** + * Accepts terms and configures units. + */ + static void verifyFirstLaunch() { + SOLO.clickOnText(ACTIVITYMYTRACKS.getString(R.string.eula_accept)); + // Click for welcome. + SOLO.clickOnText(ACTIVITYMYTRACKS.getString(R.string.generic_ok)); + // Click for choose units. + SOLO.clickOnText(ACTIVITYMYTRACKS.getString(R.string.generic_ok)); + INSTRUMENTATION.waitForIdleSync(); + } + + /** + * Creates a simple track which can be used by subsequent test. + * + * @param numberOfGpsData number of simulated Gps data + */ + static void createSimpleTrack(int numberOfGpsData) { + startRecording(); + EndToEndTestUtils.sendGps(numberOfGpsData); + stopRecording(true); + } + + /** + * Starts recoding track. + */ + static void startRecording() { + if (HAS_ACTIONBAR) { + Button startButton = getButtonOnScreen(ACTIVITYMYTRACKS.getString(R.string.menu_record_track)); + // In case a track is recording. + if (startButton == null) { + stopRecording(true); + startButton = getButtonOnScreen(ACTIVITYMYTRACKS.getString(R.string.menu_record_track)); + } + SOLO.clickOnView(startButton); + } else { + SOLO.sendKey(KeyEvent.KEYCODE_MENU); + if (!SOLO.searchText(ACTIVITYMYTRACKS.getString(R.string.menu_record_track))) { + // Check if in TrackDetailActivity. + if (SOLO.searchText(ACTIVITYMYTRACKS.getString(R.string.menu_play))) { + SOLO.goBack(); + } else { + // In case a track is recording. + stopRecording(true); + SOLO.sendKey(KeyEvent.KEYCODE_MENU); + } + } + INSTRUMENTATION.waitForIdleSync(); + SOLO.clickOnText(ACTIVITYMYTRACKS.getString(R.string.menu_record_track)); + } + } + + /** + * Stops recoding track. + * + * @param isSave ture means should save this track + */ + static void stopRecording(boolean isSave) { + INSTRUMENTATION.waitForIdleSync(); + if (HAS_ACTIONBAR) { + SOLO.clickOnView(getButtonOnScreen(ACTIVITYMYTRACKS.getString(R.string.menu_stop_recording))); + } else { + SOLO.sendKey(KeyEvent.KEYCODE_MENU); + INSTRUMENTATION.waitForIdleSync(); + SOLO.clickOnText(ACTIVITYMYTRACKS.getString(R.string.menu_stop_recording)); + } + if (isSave) { + INSTRUMENTATION.waitForIdleSync(); + // Make every track name is unique to make sure every check can be + // trusted. + EndToEndTestUtils.TRACK_NAME = EndToEndTestUtils.TRACK_NAME_PREFIX + + System.currentTimeMillis(); + SOLO.enterText(0, TRACK_NAME); + SOLO.clickLongOnText(ACTIVITYMYTRACKS.getString(R.string.generic_save)); + } + } + + /** + * Deletes a kind of track in MyTracks folder. + * + * @param trackKind the kind of track + */ + static void deleteExportedFiles(String trackKind) { + File[] allFiles = (new File(FileUtils.buildExternalDirectoryPath(trackKind.toLowerCase()))) + .listFiles(); + if (allFiles != null) { + for (File oneFile : allFiles) { + oneFile.delete(); + } + } + } + + /** + * Gets a kind of exported files. + * + * @param trackKind the kind of track + * @return files array of such kind of exported tracks + */ + static File[] getExportedFiles(final String trackKind) { + String filePath = FileUtils.buildExternalDirectoryPath(trackKind); + FileFilter filter = new FileFilter() { + @Override + public boolean accept(File pathname) { + return pathname.getName().indexOf("." + trackKind) > 0; + } + }; + return (new File(filePath)).listFiles(filter); + } + + /** + * Saves a track to a kind of file in SD card. + * + * @param trackKind the kind of track + */ + static void saveTrackToSdCard(String trackKind) { + deleteExportedFiles(trackKind); + INSTRUMENTATION.waitForIdleSync(); + SOLO.sendKey(KeyEvent.KEYCODE_MENU); + INSTRUMENTATION.waitForIdleSync(); + SOLO.clickOnText(ACTIVITYMYTRACKS.getString(R.string.menu_save)); + SOLO.clickOnText(trackKind.toUpperCase()); + rotateAllActivities(); + SOLO.waitForText(ACTIVITYMYTRACKS.getString(R.string.generic_success_title)); + } + + /** + * Checks if a button is existed in the screen. + * + * @param buttonName the name string of the button + * @return the button to search, and null means can not find the button + */ + static Button getButtonOnScreen(String buttonName) { + ArrayList