diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/sync/SyncUtils.java b/MyTracks/src/com/google/android/apps/mytracks/io/sync/SyncUtils.java index 53e71a149..fb2d2b966 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/io/sync/SyncUtils.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/sync/SyncUtils.java @@ -38,6 +38,7 @@ import com.google.api.services.drive.DriveScopes; import com.google.api.services.drive.model.File; import com.google.api.services.drive.model.FileList; import com.google.api.services.drive.model.ParentReference; +import com.google.common.annotations.VisibleForTesting; import android.accounts.Account; import android.accounts.AccountManager; @@ -74,9 +75,10 @@ public class SyncUtils { public static final String KML_MIME_TYPE = "application/vnd.google-earth.kml+xml"; public static final String GET_KML_FILES_QUERY = "'%s' in parents and mimeType = '" + KML_MIME_TYPE + "' and trashed = false"; - + private static final String FOLDER_MIME_TYPE = "application/vnd.google-apps.folder"; - private static final String GET_MY_TRACKS_FOLDER_QUERY = + @VisibleForTesting + public static final String GET_MY_TRACKS_FOLDER_QUERY = "'root' in parents and title = '%s' and mimeType = '" + FOLDER_MIME_TYPE + "' and trashed = false"; diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/io/sendtogoogle/SendRequestTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/io/sendtogoogle/SendRequestTest.java index f9ff8ab5d..00ba4d282 100644 --- a/MyTracksTest/src/com/google/android/apps/mytracks/io/sendtogoogle/SendRequestTest.java +++ b/MyTracksTest/src/com/google/android/apps/mytracks/io/sendtogoogle/SendRequestTest.java @@ -141,6 +141,8 @@ public class SendRequestTest extends AndroidTestCase { parcel.writeLong(2); parcel.writeString(""); parcel.writeString(""); + parcel.writeString(""); + parcel.writeByte((byte) 1); parcel.writeByte((byte) 1); parcel.writeByte((byte) 1); parcel.writeByte((byte) 1); @@ -151,17 +153,21 @@ public class SendRequestTest extends AndroidTestCase { parcel.writeByte((byte) 1); parcel.writeByte((byte) 1); parcel.writeByte((byte) 1); + parcel.writeByte((byte) 1); parcel.setDataPosition(0); sendRequest = SendRequest.CREATOR.createFromParcel(parcel); assertEquals(2, sendRequest.getTrackId()); assertEquals("", sendRequest.getSharingAppPackageName()); assertEquals("", sendRequest.getSharingAppClassName()); + assertEquals("", sendRequest.getAcl()); + assertTrue(sendRequest.isSendDrive()); assertTrue(sendRequest.isSendMaps()); assertTrue(sendRequest.isSendFusionTables()); assertTrue(sendRequest.isSendDocs()); assertTrue(sendRequest.isNewMap()); assertEquals(account, sendRequest.getAccount()); assertEquals(MAPID, sendRequest.getMapId()); + assertTrue(sendRequest.isDriveSuccess()); assertTrue(sendRequest.isMapsSuccess()); assertTrue(sendRequest.isFusionTablesSuccess()); assertTrue(sendRequest.isDocsSuccess()); @@ -176,6 +182,8 @@ public class SendRequestTest extends AndroidTestCase { parcel.writeLong(4); parcel.writeString(null); parcel.writeString(null); + parcel.writeString(null); + parcel.writeByte((byte) 0); parcel.writeByte((byte) 0); parcel.writeByte((byte) 0); parcel.writeByte((byte) 0); @@ -186,17 +194,21 @@ public class SendRequestTest extends AndroidTestCase { parcel.writeByte((byte) 0); parcel.writeByte((byte) 0); parcel.writeByte((byte) 0); + parcel.writeByte((byte) 0); parcel.setDataPosition(0); sendRequest = SendRequest.CREATOR.createFromParcel(parcel); assertEquals(4, sendRequest.getTrackId()); assertNull(sendRequest.getSharingAppPackageName()); assertNull(sendRequest.getSharingAppClassName()); + assertNull(sendRequest.getAcl()); + assertFalse(sendRequest.isSendDrive()); assertFalse(sendRequest.isSendMaps()); assertFalse(sendRequest.isSendFusionTables()); assertFalse(sendRequest.isSendDocs()); assertFalse(sendRequest.isNewMap()); assertEquals(account, sendRequest.getAccount()); assertEquals(MAPID, sendRequest.getMapId()); + assertFalse(sendRequest.isDriveSuccess()); assertFalse(sendRequest.isMapsSuccess()); assertFalse(sendRequest.isFusionTablesSuccess()); assertFalse(sendRequest.isDocsSuccess()); @@ -214,24 +226,30 @@ public class SendRequestTest extends AndroidTestCase { long trackId = parcel.readLong(); String sharingAppPackageName = parcel.readString(); String sharingAppClassName = parcel.readString(); + String acl = parcel.readString(); + boolean sendDrive = parcel.readByte() == 1; boolean sendMaps = parcel.readByte() == 1; boolean sendFusionTables = parcel.readByte() == 1; boolean sendDocs = parcel.readByte() == 1; boolean newMap = parcel.readByte() == 1; Parcelable account = parcel.readParcelable(null); String mapId = parcel.readString(); + boolean driveSuccess = parcel.readByte() == 1; boolean mapsSuccess = parcel.readByte() == 1; boolean fusionTablesSuccess = parcel.readByte() == 1; boolean docsSuccess = parcel.readByte() == 1; assertEquals(1, trackId); assertNull(sharingAppPackageName); assertNull(sharingAppClassName); + assertNull(acl); + assertFalse(sendDrive); assertFalse(sendMaps); assertFalse(sendFusionTables); assertFalse(sendDocs); assertFalse(newMap); assertNull(account); assertNull(mapId); + assertFalse(driveSuccess); assertFalse(mapsSuccess); assertFalse(fusionTablesSuccess); assertFalse(docsSuccess); @@ -243,7 +261,9 @@ public class SendRequestTest extends AndroidTestCase { public void testWriteToParcel() { sendRequest = new SendRequest(4); sendRequest.setSharingAppPackageName("package"); - sendRequest.setSharingAppClassName("class"); + sendRequest.setSharingAppClassName("class"); + sendRequest.setAcl("acl"); + sendRequest.setSendDrive(true); sendRequest.setSendMaps(true); sendRequest.setSendFusionTables(true); sendRequest.setSendDocs(true); @@ -252,6 +272,7 @@ public class SendRequestTest extends AndroidTestCase { sendRequest.setAccount(accountNew); sendRequest.setMapId(MAPID); sendRequest.setMapsSuccess(true); + sendRequest.setDriveSuccess(true); sendRequest.setFusionTablesSuccess(true); sendRequest.setDocsSuccess(true); Parcel parcel = Parcel.obtain(); @@ -261,24 +282,30 @@ public class SendRequestTest extends AndroidTestCase { long trackId = parcel.readLong(); String sharingAppPackageName = parcel.readString(); String sharingAppClassName = parcel.readString(); + String acl = parcel.readString(); + boolean sendDrive = parcel.readByte() == 1; boolean sendMaps = parcel.readByte() == 1; boolean sendFusionTables = parcel.readByte() == 1; boolean sendDocs = parcel.readByte() == 1; boolean newMap = parcel.readByte() == 1; Parcelable account = parcel.readParcelable(null); String mapId = parcel.readString(); + boolean driveSuccess = parcel.readByte() == 1; boolean mapsSuccess = parcel.readByte() == 1; boolean fusionTablesSuccess = parcel.readByte() == 1; boolean docsSuccess = parcel.readByte() == 1; assertEquals(4, trackId); assertEquals("package", sharingAppPackageName); assertEquals("class", sharingAppClassName); + assertEquals("acl", acl); + assertTrue(sendDrive); assertTrue(sendMaps); assertTrue(sendFusionTables); assertTrue(sendDocs); assertTrue(newMap); assertEquals(accountNew, account); assertEquals(MAPID, mapId); + assertTrue(driveSuccess); assertTrue(mapsSuccess); assertTrue(fusionTablesSuccess); assertTrue(docsSuccess); diff --git a/MyTracksTest_E2E/src/com/google/android/apps/mytracks/endtoendtest/DeleteTest.java b/MyTracksTest_E2E/src/com/google/android/apps/mytracks/endtoendtest/DeleteTest.java index 5993db73d..563140fbb 100644 --- a/MyTracksTest_E2E/src/com/google/android/apps/mytracks/endtoendtest/DeleteTest.java +++ b/MyTracksTest_E2E/src/com/google/android/apps/mytracks/endtoendtest/DeleteTest.java @@ -93,6 +93,7 @@ public class DeleteTest extends ActivityInstrumentationTestCase2 3) { + deleteAllTracks(); + } + + resetAllSettings(activityMyTracks, false); + instrumentation.waitForIdleSync(); + // Check whether is under recording. If previous test failed, the recording // may not be recording. if (isUnderRecording()) { @@ -415,6 +421,8 @@ public class EndToEndTestUtils { if (isClick) { SOLO.scrollUp(); SOLO.clickOnView(oneTrack); + EndToEndTestUtils.SOLO.waitForText(activityMytracks + .getString(R.string.track_detail_chart_tab)); } return false; } @@ -1005,6 +1013,7 @@ public class EndToEndTestUtils { sendGps(30); View myLocation = SOLO.getCurrentActivity().findViewById(R.id.map_my_location); + instrumentation.waitForIdleSync(); // Find the My Location button in another if null. if (myLocation == null) { ArrayList aa = SOLO.getCurrentImageButtons(); diff --git a/MyTracksTest_E2E/src/com/google/android/apps/mytracks/endtoendtest/ExportAndImportTest.java b/MyTracksTest_E2E/src/com/google/android/apps/mytracks/endtoendtest/ExportAndImportTest.java index ae0a6150a..ee994062d 100644 --- a/MyTracksTest_E2E/src/com/google/android/apps/mytracks/endtoendtest/ExportAndImportTest.java +++ b/MyTracksTest_E2E/src/com/google/android/apps/mytracks/endtoendtest/ExportAndImportTest.java @@ -111,6 +111,7 @@ public class ExportAndImportTest extends ActivityInstrumentationTestCase2 { + + private Drive drive; + private Instrumentation instrumentation; + private TrackListActivity trackListActivity; + + public MultiAccountsSyncTest() { + super(TrackListActivity.class); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + instrumentation = getInstrumentation(); + trackListActivity = getActivity(); + drive = SyncTestUtils.setUpForSyncTest(instrumentation, trackListActivity); + } + + /** + * Tests sync tracks with Google Drive of two accounts with following + * sequence: + *
    + *
  • 1. Enable sync with account1.
  • + *
  • 2. Create a track.
  • + *
  • 3. Enable sync with account2.
  • + *
  • 4. Create a track.
  • + *
  • 5. Sync and check
  • + *
  • 6. Enable sync with account1.
  • + *
  • 7. Sync and check
  • + *
  • 8. Enable sync with account2.
  • + *
  • 9. Check
  • + *
+ * + * @throws IOException + */ + public void testSyncTracksWithMultiAccounts() throws IOException { + if (!SyncTestUtils.runSyncTest) { + return; + } + SyncTestUtils.enableSync(GoogleUtils.ACCOUNT_NAME_1); + // Create tracks with first track. + EndToEndTestUtils.createSimpleTrack(0, true); + + // Create tracks with second track. + SyncTestUtils.enableSync(GoogleUtils.ACCOUNT_NAME_2); + EndToEndTestUtils.createSimpleTrack(0, true); + + // Sync with Google Drive and then check it of the second account. + EndToEndTestUtils.findMenuItem( + EndToEndTestUtils.activityMytracks.getString(R.string.menu_sync_now), true); + drive = SyncTestUtils.getGoogleDrive(trackListActivity.getApplicationContext()); + SyncTestUtils.checkFilesNumber(drive); + + // Check Google Drive of the first account. + SyncTestUtils.enableSync(GoogleUtils.ACCOUNT_NAME_1); + EndToEndTestUtils.findMenuItem( + EndToEndTestUtils.activityMytracks.getString(R.string.menu_sync_now), true); + drive = SyncTestUtils.getGoogleDrive(trackListActivity.getApplicationContext()); + SyncTestUtils.checkFilesNumber(drive); + + // Back to account1 change check that files are still existed. + SyncTestUtils.enableSync(GoogleUtils.ACCOUNT_NAME_2); + drive = SyncTestUtils.getGoogleDrive(trackListActivity.getApplicationContext()); + SyncTestUtils.checkFilesNumber(drive); + } + + /** + * Tests the behavior of MyTracks about delete operation and switch accounts + * with following sequence.: + *
    + *
  • 1. Create 3 tracks.
  • + *
  • 2. Delete 1 track.
  • + *
  • 3. Sync with account2(account2 should have 2 files).
  • + *
  • 4. Delete 1 track (account2 should have 1 file).
  • + *
  • 5. Sync with account 1 (account 1 should have 1 file, account2 should + * also have 1 file).
  • + *
+ * + * @throws IOException + */ + public void testDeleteTracksWithMultiAccounts() throws IOException { + if (!SyncTestUtils.runSyncTest) { + return; + } + EndToEndTestUtils.createSimpleTrack(0, true); + EndToEndTestUtils.createSimpleTrack(0, true); + EndToEndTestUtils.createSimpleTrack(0, true); + + // Delete one track. + EndToEndTestUtils.SOLO.clickOnView(EndToEndTestUtils.SOLO.getCurrentListViews().get(0) + .getChildAt(0)); + EndToEndTestUtils.SOLO.clickOnMenuItem(EndToEndTestUtils.activityMytracks + .getString(R.string.menu_delete)); + EndToEndTestUtils.SOLO.clickOnText(EndToEndTestUtils.activityMytracks + .getString(R.string.generic_ok)); + + // Switch account and delete another track. + SyncTestUtils.enableSync(GoogleUtils.ACCOUNT_NAME_2); + EndToEndTestUtils.SOLO.clickOnView(EndToEndTestUtils.SOLO.getCurrentListViews().get(0) + .getChildAt(0)); + EndToEndTestUtils.SOLO.clickOnMenuItem(EndToEndTestUtils.activityMytracks + .getString(R.string.menu_delete)); + EndToEndTestUtils.SOLO.clickOnText(EndToEndTestUtils.activityMytracks + .getString(R.string.generic_ok)); + + // Check Google Drive of the first account. + SyncTestUtils.enableSync(GoogleUtils.ACCOUNT_NAME_1); + EndToEndTestUtils.findMenuItem( + EndToEndTestUtils.activityMytracks.getString(R.string.menu_sync_now), true); + drive = SyncTestUtils.getGoogleDrive(trackListActivity.getApplicationContext()); + SyncTestUtils.checkFilesNumber(drive); + + // Check Google Drive of the second account. + SyncTestUtils.enableSync(GoogleUtils.ACCOUNT_NAME_2); + EndToEndTestUtils.findMenuItem( + EndToEndTestUtils.activityMytracks.getString(R.string.menu_sync_now), true); + drive = SyncTestUtils.getGoogleDrive(trackListActivity.getApplicationContext()); + SyncTestUtils.checkFilesNumber(drive); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + EndToEndTestUtils.SOLO.finishOpenedActivities(); + } +} diff --git a/MyTracksTest_E2E/src/com/google/android/apps/mytracks/endtoendtest/sync/SyncDriveWithMyTracksTest.java b/MyTracksTest_E2E/src/com/google/android/apps/mytracks/endtoendtest/sync/SyncDriveWithMyTracksTest.java new file mode 100644 index 000000000..a10273236 --- /dev/null +++ b/MyTracksTest_E2E/src/com/google/android/apps/mytracks/endtoendtest/sync/SyncDriveWithMyTracksTest.java @@ -0,0 +1,161 @@ +/* + * Copyright 2013 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.sync; + +import com.google.android.apps.mytracks.TrackListActivity; +import com.google.android.apps.mytracks.endtoendtest.EndToEndTestUtils; +import com.google.android.maps.mytracks.R; +import com.google.api.services.drive.Drive; + +import android.app.Instrumentation; +import android.test.ActivityInstrumentationTestCase2; +import android.view.KeyEvent; + +import java.io.IOException; + +/** + * Tests making changes on Google Drive when syncing My Tracks with Google Drive. + * + * @author Youtao Liu + */ +public class SyncDriveWithMyTracksTest extends ActivityInstrumentationTestCase2 { + + private Drive drive; + private Instrumentation instrumentation; + private TrackListActivity trackListActivity; + + public SyncDriveWithMyTracksTest() { + super(TrackListActivity.class); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + instrumentation = getInstrumentation(); + trackListActivity = getActivity(); + drive = SyncTestUtils.setUpForSyncTest(instrumentation, trackListActivity); + } + + /** + * Deletes all tracks in MyTracks and checks in Google Drive. + * + * @throws IOException + */ + public void testDeleteAllTracksInMyTracks() throws IOException { + if (!SyncTestUtils.runSyncTest) { + return; + } + EndToEndTestUtils.deleteAllTracks(); + EndToEndTestUtils.findMenuItem( + EndToEndTestUtils.activityMytracks.getString(R.string.menu_sync_now), true); + SyncTestUtils.checkFilesNumber(drive); + } + + /** + * Deletes one track in MyTracks and checks it in Google Drive. + * + * @throws IOException + */ + public void testDeleteOneTracksInMyTracks() throws IOException { + if (!SyncTestUtils.runSyncTest) { + return; + } + EndToEndTestUtils.createTrackIfEmpty(2, false); + EndToEndTestUtils.SOLO.clickOnMenuItem(EndToEndTestUtils.activityMytracks + .getString(R.string.menu_delete)); + EndToEndTestUtils.SOLO.clickOnText(EndToEndTestUtils.activityMytracks + .getString(R.string.generic_ok)); + EndToEndTestUtils.findMenuItem( + EndToEndTestUtils.activityMytracks.getString(R.string.menu_sync_now), true); + SyncTestUtils.checkFile(EndToEndTestUtils.trackName, false, drive); + } + + /** + * Creates one empty track and one non-empty track in MyTracks and then check + * them in Google Drive. + * + * @throws IOException + */ + public void testCreateTracksInMyTracks() throws IOException { + if (!SyncTestUtils.runSyncTest) { + return; + } + EndToEndTestUtils.deleteAllTracks(); + EndToEndTestUtils.createSimpleTrack(0, true); + EndToEndTestUtils.createSimpleTrack(3, true); + EndToEndTestUtils.findMenuItem( + EndToEndTestUtils.activityMytracks.getString(R.string.menu_sync_now), true); + SyncTestUtils.checkFilesNumber(drive); + } + + /** + * Edits a tracks in MyTracks and checks it on Google Drive after sync. + * + * @throws IOException + */ + public void testEditTrackInMyTracks() throws IOException { + if (!SyncTestUtils.runSyncTest) { + return; + } + EndToEndTestUtils.createTrackIfEmpty(3, true); + + // Sync this track. + EndToEndTestUtils.findMenuItem( + EndToEndTestUtils.activityMytracks.getString(R.string.menu_sync_now), true); + SyncTestUtils.checkFile(EndToEndTestUtils.trackName, true, drive); + String oldTrack = SyncTestUtils.getContentOfFile( + SyncTestUtils.getFile(EndToEndTestUtils.trackName, drive), drive); + + String oldTrackName = EndToEndTestUtils.trackName; + + // Edit this track. + EndToEndTestUtils.SOLO.clickOnText(EndToEndTestUtils.trackName); + EndToEndTestUtils.findMenuItem(trackListActivity.getString(R.string.menu_edit), true); + String newTrackName = EndToEndTestUtils.TRACK_NAME_PREFIX + "_new" + System.currentTimeMillis(); + String newType = EndToEndTestUtils.activityType + newTrackName; + String newDesc = "desc" + newTrackName; + instrumentation.waitForIdleSync(); + EndToEndTestUtils.SOLO.waitForText(trackListActivity.getString(R.string.generic_save)); + sendKeys(KeyEvent.KEYCODE_DEL); + EndToEndTestUtils.enterTextAvoidSoftKeyBoard(0, newTrackName); + EndToEndTestUtils.enterTextAvoidSoftKeyBoard(1, newType); + EndToEndTestUtils.enterTextAvoidSoftKeyBoard(2, newDesc); + EndToEndTestUtils.SOLO.clickOnButton(trackListActivity.getString(R.string.generic_save)); + instrumentation.waitForIdleSync(); + EndToEndTestUtils.SOLO.goBack(); + instrumentation.waitForIdleSync(); + + // Sync again. + EndToEndTestUtils.findMenuItem( + EndToEndTestUtils.activityMytracks.getString(R.string.menu_sync_now), true); + + // Check. + SyncTestUtils.checkFile(oldTrackName, false, drive); + SyncTestUtils.checkFile(newTrackName, true, drive); + String newTrack = SyncTestUtils.getContentOfFile(SyncTestUtils.getFile(newTrackName, drive), + drive); + assertNotSame(oldTrack, newTrack); + assertTrue(newTrack.indexOf(newTrackName) > 0); + assertTrue(newTrack.indexOf(newType) > 0); + assertTrue(newTrack.indexOf(newDesc) > 0); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + EndToEndTestUtils.SOLO.finishOpenedActivities(); + } +} diff --git a/MyTracksTest_E2E/src/com/google/android/apps/mytracks/endtoendtest/sync/SyncMyTracksWithDriveTest.java b/MyTracksTest_E2E/src/com/google/android/apps/mytracks/endtoendtest/sync/SyncMyTracksWithDriveTest.java new file mode 100644 index 000000000..3b2f1652a --- /dev/null +++ b/MyTracksTest_E2E/src/com/google/android/apps/mytracks/endtoendtest/sync/SyncMyTracksWithDriveTest.java @@ -0,0 +1,121 @@ +/* + * Copyright 2013 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.sync; + +import com.google.android.apps.mytracks.TrackListActivity; +import com.google.android.apps.mytracks.endtoendtest.EndToEndTestUtils; +import com.google.android.maps.mytracks.R; +import com.google.api.services.drive.Drive; +import com.google.api.services.drive.model.File; + +import android.app.Instrumentation; +import android.test.ActivityInstrumentationTestCase2; + +import java.io.IOException; + +/** + * Tests making changes on My Tracks when syncing My Tracks with Google Drive. + * + * @author Youtao Liu + */ +public class SyncMyTracksWithDriveTest extends ActivityInstrumentationTestCase2 { + + private Drive drive; + private Instrumentation instrumentation; + private TrackListActivity trackListActivity; + + public SyncMyTracksWithDriveTest() { + super(TrackListActivity.class); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + instrumentation = getInstrumentation(); + trackListActivity = getActivity(); + drive = SyncTestUtils.setUpForSyncTest(instrumentation, trackListActivity); + } + + /** + * Deletes all tracks on Google Drive and checks in MyTracks. + * + * @throws IOException + */ + public void testDeleteAllTracksOnDrive() throws IOException { + if (!SyncTestUtils.runSyncTest) { + return; + } + EndToEndTestUtils.createTrackIfEmpty(0, true); + EndToEndTestUtils.findMenuItem( + EndToEndTestUtils.activityMytracks.getString(R.string.menu_sync_now), true); + SyncTestUtils.checkFilesNumber(drive); + + SyncTestUtils.removeKMLFiles(drive); + EndToEndTestUtils.findMenuItem( + EndToEndTestUtils.activityMytracks.getString(R.string.menu_sync_now), true); + SyncTestUtils.checkTracksNumber(0); + } + + /** + * Deletes one file on Google Drive and checks it in MyTracks. + * + * @throws IOException + */ + public void testDeleteOneFileOnDrive() throws IOException { + if (!SyncTestUtils.runSyncTest) { + return; + } + instrumentation.waitForIdleSync(); + EndToEndTestUtils.createSimpleTrack(0, true); + EndToEndTestUtils.createSimpleTrack(0, true); + EndToEndTestUtils.findMenuItem( + EndToEndTestUtils.activityMytracks.getString(R.string.menu_sync_now), true); + SyncTestUtils.checkFilesNumber(drive); + + // Remove one track from Google Drive + File file = SyncTestUtils.getFile(EndToEndTestUtils.trackName, drive); + SyncTestUtils.removeFile(file, drive); + EndToEndTestUtils.findMenuItem( + EndToEndTestUtils.activityMytracks.getString(R.string.menu_sync_now), true); + SyncTestUtils.checkFilesNumber(drive); + SyncTestUtils.checkTracksNumber(1); + } + + /** + * Tests deleting and creating MyTracks folder on Google Dive by MyTracks. + * + * @throws IOException + */ + public void testCreateMyTracksOnDrive() throws IOException { + if (!SyncTestUtils.runSyncTest) { + return; + } + instrumentation.waitForIdleSync(); + EndToEndTestUtils.createSimpleTrack(0, true); + EndToEndTestUtils.createSimpleTrack(0, true); + EndToEndTestUtils.findMenuItem( + EndToEndTestUtils.activityMytracks.getString(R.string.menu_sync_now), true); + instrumentation.waitForIdleSync(); + SyncTestUtils.checkFilesNumber(drive); + File folder = SyncTestUtils.getMyTracksFolder(trackListActivity.getApplicationContext(), drive); + assertNotNull(folder); + + SyncTestUtils.removeFile(folder, drive); + EndToEndTestUtils.findMenuItem( + EndToEndTestUtils.activityMytracks.getString(R.string.menu_sync_now), true); + SyncTestUtils.checkFilesNumber(drive); + } +} diff --git a/MyTracksTest_E2E/src/com/google/android/apps/mytracks/endtoendtest/sync/SyncTestUtils.java b/MyTracksTest_E2E/src/com/google/android/apps/mytracks/endtoendtest/sync/SyncTestUtils.java new file mode 100644 index 000000000..3420e6ba3 --- /dev/null +++ b/MyTracksTest_E2E/src/com/google/android/apps/mytracks/endtoendtest/sync/SyncTestUtils.java @@ -0,0 +1,345 @@ +/* + * Copyright 2013 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.sync; + +import com.google.android.apps.mytracks.TrackListActivity; +import com.google.android.apps.mytracks.endtoendtest.EndToEndTestUtils; +import com.google.android.apps.mytracks.endtoendtest.GoogleUtils; +import com.google.android.apps.mytracks.io.sync.SyncUtils; +import com.google.android.apps.mytracks.util.PreferencesUtils; +import com.google.android.maps.mytracks.R; +import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential; +import com.google.api.client.googleapis.json.GoogleJsonResponseException; +import com.google.api.client.http.GenericUrl; +import com.google.api.client.http.HttpResponse; +import com.google.api.services.drive.Drive; +import com.google.api.services.drive.model.File; +import com.google.api.services.drive.model.FileList; + +import android.app.Instrumentation; +import android.content.Context; +import android.util.Log; +import android.widget.CheckBox; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +import junit.framework.Assert; + +/** + * Utilites for Google Drive sync endtoend test. + * + * @author Youtao Liu + */ +public class SyncTestUtils { + + public static boolean isCheckedRunSyncTest = false; + public static boolean runSyncTest = false; + public static final String KML_FILE_POSTFIX = ".kml"; + public static final long MAX_TIME_TO_WAIT_SYNC = 50000; + + /** + * Sets up sync tests. + * + * @param instrumentation the instrumentation is used for test + * @param trackListActivity the startup activity + * @return a Google Drive object + * @throws IOException + */ + public static Drive setUpForSyncTest(Instrumentation instrumentation, + TrackListActivity trackListActivity) throws IOException { + if (runSyncTest || !isCheckedRunSyncTest) { + EndToEndTestUtils.setupForAllTest(instrumentation, trackListActivity); + } + if (!isCheckedRunSyncTest) { + runSyncTest = canRunSyncTest(); + isCheckedRunSyncTest = true; + } + if (runSyncTest) { + EndToEndTestUtils.deleteAllTracks(); + SyncTestUtils.enableSync(GoogleUtils.ACCOUNT_NAME_1); + Drive drive1 = SyncTestUtils.getGoogleDrive(EndToEndTestUtils.activityMytracks + .getApplicationContext()); + removeKMLFiles(drive1); + SyncTestUtils.enableSync(GoogleUtils.ACCOUNT_NAME_2); + Drive drive2 = SyncTestUtils.getGoogleDrive(EndToEndTestUtils.activityMytracks + .getApplicationContext()); + removeKMLFiles(drive2); + return drive2; + } + return null; + } + + /** + * Runs sync tests when both test accounts are bound with the devices. + * + * @return true means can run sync tests in this device + */ + public static boolean canRunSyncTest() { + EndToEndTestUtils.findMenuItem( + EndToEndTestUtils.activityMytracks.getString(R.string.menu_settings), true); + EndToEndTestUtils.SOLO.clickOnText(EndToEndTestUtils.activityMytracks + .getString(R.string.settings_google)); + EndToEndTestUtils.SOLO.clickOnText(EndToEndTestUtils.activityMytracks + .getString(R.string.settings_google_account_title)); + boolean canRunSyncE2ETest = EndToEndTestUtils.SOLO.waitForText(GoogleUtils.ACCOUNT_NAME_1, 1, + EndToEndTestUtils.SHORT_WAIT_TIME) + && EndToEndTestUtils.SOLO.waitForText(GoogleUtils.ACCOUNT_NAME_2, 1, + EndToEndTestUtils.TINY_WAIT_TIME); + EndToEndTestUtils.SOLO.clickOnText(EndToEndTestUtils.activityMytracks + .getString(R.string.generic_cancel)); + EndToEndTestUtils.SOLO.goBack(); + EndToEndTestUtils.SOLO.goBack(); + return canRunSyncE2ETest; + } + + /** + * Gets drive object of Google Drive. + * + * @param context the context of application + * @return a Google Drive object + */ + public static Drive getGoogleDrive(Context context) { + String googleAccount = PreferencesUtils.getString(context, R.string.google_account_key, + PreferencesUtils.GOOGLE_ACCOUNT_DEFAULT); + GoogleAccountCredential credential = SyncUtils.getCredential(context, googleAccount); + return SyncUtils.getDriveService(credential); + } + + /** + * Gets KML files from Google Drive of current account. + * + * @param context the context of application + * @param drive a Google Drive object + * @return KML file on Google drive + * @throws IOException + */ + public static List getDriveFiles(Context context, Drive drive) throws IOException { + File folder = SyncTestUtils.getMyTracksFolder(context, drive); + if (folder == null) { + return new ArrayList(); + } + String folderId = folder.getId(); + return drive.files().list() + .setQ(String.format(Locale.US, SyncUtils.GET_KML_FILES_QUERY, folderId)).execute() + .getItems(); + } + + /** + * Finds whether a file is existed by the name of track. + * + * @param trackName name of track + * @param drive a Google Drive object + * @return the file be found + * @throws IOException + */ + public static File getFile(String trackName, Drive drive) throws IOException { + List files = getDriveFiles(EndToEndTestUtils.activityMytracks.getApplicationContext(), + drive); + for (int i = 0; i < files.size(); i++) { + File file = files.get(i); + String title = file.getTitle(); + if (title.equals(trackName + KML_FILE_POSTFIX)) { + return file; + } + } + return null; + } + + /** + * Removes all KML files on Google Drive. + * + * @param drive a Google Drive object + * @throws IOException + */ + public static void removeKMLFiles(Drive drive) throws IOException { + List files = SyncTestUtils.getDriveFiles( + EndToEndTestUtils.activityMytracks.getApplicationContext(), drive); + for (int i = 0; i < files.size(); i++) { + File file = files.get(i); + removeFile(file, drive); + } + } + + /** + * Removes one file on Google Drive. + * + * @param file the file to remove + * @param drive a Google Drive object + * @throws IOException + */ + public static void removeFile(File file, Drive drive) throws IOException { + drive.files().trash(file.getId()).execute(); + } + + /** + * Enables sync feature in MyTracks settings. + * + * @param accountName the account which is used to sync with + */ + public static void enableSync(String accountName) { + EndToEndTestUtils.findMenuItem( + EndToEndTestUtils.activityMytracks.getString(R.string.menu_settings), true); + EndToEndTestUtils.SOLO.clickOnText(EndToEndTestUtils.activityMytracks + .getString(R.string.settings_google)); + EndToEndTestUtils.SOLO.clickOnText(EndToEndTestUtils.activityMytracks + .getString(R.string.settings_google_account_title)); + + // Whether test account is bound. + if (EndToEndTestUtils.SOLO.waitForText(accountName, 1, EndToEndTestUtils.TINY_WAIT_TIME)) { + EndToEndTestUtils.SOLO.clickOnText(accountName); + EndToEndTestUtils.instrumentation.waitForIdleSync(); + if (EndToEndTestUtils.SOLO.waitForText( + EndToEndTestUtils.activityMytracks.getString( + R.string.settings_google_account_confirm_message).split("%")[0], 1, + EndToEndTestUtils.SHORT_WAIT_TIME)) { + EndToEndTestUtils.SOLO.clickOnText(EndToEndTestUtils.activityMytracks + .getString(R.string.generic_ok)); + } + } else { + Assert.fail(); + return; + } + + EndToEndTestUtils.instrumentation.waitForIdleSync(); + CheckBox syncCheckBox = EndToEndTestUtils.SOLO.getCurrentCheckBoxes().get(0); + if (!syncCheckBox.isChecked()) { + EndToEndTestUtils.SOLO.clickOnText(EndToEndTestUtils.activityMytracks + .getString(R.string.settings_google_drive_sync_title)); + + EndToEndTestUtils.SOLO.waitForText( + EndToEndTestUtils.activityMytracks.getString( + R.string.settings_google_drive_sync_confirm_message).split("%")[0], 1, + EndToEndTestUtils.SHORT_WAIT_TIME); + Assert.assertTrue(EndToEndTestUtils.SOLO.searchText(accountName, true)); + EndToEndTestUtils.SOLO.clickOnText(EndToEndTestUtils.activityMytracks + .getString(R.string.generic_ok)); + } + EndToEndTestUtils.SOLO.goBack(); + EndToEndTestUtils.SOLO.goBack(); + } + + /** + * Checks the files number on Google Drive + * + * @param drive a Google Drive object + * @throws IOException + */ + public static void checkFilesNumber(Drive drive) throws IOException { + long startTime = System.currentTimeMillis(); + while (System.currentTimeMillis() - startTime < MAX_TIME_TO_WAIT_SYNC) { + try { + int trackNumber = EndToEndTestUtils.SOLO.getCurrentListViews().get(0).getCount(); + List files = getDriveFiles( + EndToEndTestUtils.activityMytracks.getApplicationContext(), drive); + if (files.size() == trackNumber) { + return; + } + } catch (GoogleJsonResponseException e) { + EndToEndTestUtils.sleep(EndToEndTestUtils.SHORT_WAIT_TIME); + } + } + Assert.fail(); + } + + /** + * Checks the files number on Google Drive + * + * @param number number of files on Google Drive + */ + public static void checkTracksNumber(int number) { + long startTime = System.currentTimeMillis(); + while (System.currentTimeMillis() - startTime < MAX_TIME_TO_WAIT_SYNC) { + int trackNumber = EndToEndTestUtils.SOLO.getCurrentListViews().get(0).getCount(); + if (trackNumber == number) { + return; + } + } + Assert.fail(); + } + + /** + * Checks one file on Google Drive + * + * @param trackName the name of track + * @param shouldExist true means this track should be existed + * @param drive a Google Drive object + * @return true means the actual result is same as expectation + * @throws IOException + */ + public static boolean checkFile(String trackName, boolean shouldExist, Drive drive) + throws IOException { + long startTime = System.currentTimeMillis(); + while (System.currentTimeMillis() - startTime < MAX_TIME_TO_WAIT_SYNC) { + boolean exist = getFile(trackName, drive) != null; + if (exist == shouldExist) { + return true; + } + } + Assert.fail(); + return false; + } + + /** + * Gets the content of a file on Google Drive. + * + * @param file file to read + * @param drive a Google Drive object + * @return the string content of the file + * @throws IOException + */ + public static String getContentOfFile(File file, Drive drive) throws IOException { + HttpResponse resp = drive.getRequestFactory() + .buildGetRequest(new GenericUrl(file.getDownloadUrl())).execute(); + BufferedReader br = new BufferedReader(new InputStreamReader(resp.getContent())); + StringBuilder sb = new StringBuilder(); + String line; + while ((line = br.readLine()) != null) { + sb.append(line); + } + String fileContent = sb.toString(); + br.close(); + return fileContent; + } + + /** + * Gets the MyTracks folder on Google Drive. + * + * @param context context of application + * @param drive a Google Drive object + * @return the MyTracks folder on Google Drive + */ + public static File getMyTracksFolder(Context context, Drive drive) { + try { + String folderName = context.getString(R.string.my_tracks_app_name); + com.google.api.services.drive.Drive.Files.List list = drive.files().list() + .setQ(String.format(Locale.US, SyncUtils.GET_MY_TRACKS_FOLDER_QUERY, folderName)); + FileList result = list.execute(); + for (File file : result.getItems()) { + if (file.getTitle().equals(folderName)) { + return file; + } + } + } catch (IOException e) { + Log.e(EndToEndTestUtils.LOG_TAG, "IOException", e); + } + return null; + } +}