diff options
Diffstat (limited to '')
5 files changed, 530 insertions, 0 deletions
diff --git a/updater_sample/tests/src/com/example/android/systemupdatersample/UpdateConfigTest.java b/updater_sample/tests/src/com/example/android/systemupdatersample/UpdateConfigTest.java new file mode 100644 index 000000000..48d0e424d --- /dev/null +++ b/updater_sample/tests/src/com/example/android/systemupdatersample/UpdateConfigTest.java @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * 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.example.android.systemupdatersample; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +import android.content.Context; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import com.example.android.systemupdatersample.tests.R; +import com.google.common.io.CharStreams; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; + +import java.io.IOException; +import java.io.InputStreamReader; + +/** + * Tests for {@link UpdateConfig} + */ +@RunWith(AndroidJUnit4.class) +@SmallTest +public class UpdateConfigTest { + + private static final String JSON_NON_STREAMING = "{" + + " \"name\": \"vip update\", \"url\": \"file:///my-builds/a.zip\"," + + " \"ab_install_type\": \"NON_STREAMING\"," + + " \"ab_config\": {" + + " \"force_switch_slot\": false," + + " \"verify_payload_metadata\": false } }"; + + @Rule + public final ExpectedException thrown = ExpectedException.none(); + + private Context mContext; + private Context mTargetContext; + private String mJsonStreaming001; + + @Before + public void setUp() throws Exception { + mContext = InstrumentationRegistry.getContext(); + mTargetContext = InstrumentationRegistry.getTargetContext(); + mJsonStreaming001 = readResource(R.raw.update_config_001_stream); + } + + @Test + public void fromJson_parsesNonStreaming() throws Exception { + UpdateConfig config = UpdateConfig.fromJson(JSON_NON_STREAMING); + assertEquals("name is parsed", "vip update", config.getName()); + assertEquals("stores raw json", JSON_NON_STREAMING, config.getRawJson()); + assertSame("type is parsed", + UpdateConfig.AB_INSTALL_TYPE_NON_STREAMING, + config.getInstallType()); + assertEquals("url is parsed", "file:///my-builds/a.zip", config.getUrl()); + } + + @Test + public void fromJson_parsesStreaming() throws Exception { + UpdateConfig config = UpdateConfig.fromJson(mJsonStreaming001); + assertEquals("streaming-001", config.getName()); + assertEquals("http://foo.bar/update.zip", config.getUrl()); + assertSame(UpdateConfig.AB_INSTALL_TYPE_STREAMING, config.getInstallType()); + assertEquals("payload.bin", + config.getAbConfig().getPropertyFiles()[0].getFilename()); + assertEquals(195, config.getAbConfig().getPropertyFiles()[0].getOffset()); + assertEquals(8, config.getAbConfig().getPropertyFiles()[0].getSize()); + assertTrue(config.getAbConfig().getForceSwitchSlot()); + } + + @Test + public void getUpdatePackageFile_throwsErrorIfStreaming() throws Exception { + UpdateConfig config = UpdateConfig.fromJson(mJsonStreaming001); + thrown.expect(RuntimeException.class); + config.getUpdatePackageFile(); + } + + @Test + public void getUpdatePackageFile_throwsErrorIfNotAFile() throws Exception { + String json = "{" + + " \"name\": \"upd\", \"url\": \"http://foo.bar\"," + + " \"ab_install_type\": \"NON_STREAMING\"," + + " \"ab_config\": {" + + " \"force_switch_slot\": false," + + " \"verify_payload_metadata\": false } }"; + UpdateConfig config = UpdateConfig.fromJson(json); + thrown.expect(RuntimeException.class); + config.getUpdatePackageFile(); + } + + @Test + public void getUpdatePackageFile_works() throws Exception { + UpdateConfig c = UpdateConfig.fromJson(JSON_NON_STREAMING); + assertEquals("/my-builds/a.zip", c.getUpdatePackageFile().getAbsolutePath()); + } + + private String readResource(int id) throws IOException { + return CharStreams.toString(new InputStreamReader( + mContext.getResources().openRawResource(id))); + } +} diff --git a/updater_sample/tests/src/com/example/android/systemupdatersample/UpdateManagerTest.java b/updater_sample/tests/src/com/example/android/systemupdatersample/UpdateManagerTest.java new file mode 100644 index 000000000..5ad16d477 --- /dev/null +++ b/updater_sample/tests/src/com/example/android/systemupdatersample/UpdateManagerTest.java @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * 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.example.android.systemupdatersample; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.os.ResultReceiver; +import android.os.UpdateEngine; +import android.os.UpdateEngineCallback; +import android.support.test.InstrumentationRegistry; +import android.support.test.annotation.UiThreadTest; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import com.example.android.systemupdatersample.services.PrepareUpdateService; +import com.example.android.systemupdatersample.tests.R; +import com.google.common.collect.ImmutableList; +import com.google.common.io.CharStreams; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import java.io.IOException; +import java.io.InputStreamReader; + +/** + * Tests for {@link UpdateManager} + */ +@RunWith(AndroidJUnit4.class) +@SmallTest +public class UpdateManagerTest { + + @Rule + public MockitoRule mockito = MockitoJUnit.rule(); + + @Mock + private UpdateEngine mUpdateEngine; + @Mock + private Context mMockContext; + private UpdateManager mSubject; + private Context mTestContext; + private UpdateConfig mStreamingUpdate002; + + @Before + public void setUp() throws Exception { + mTestContext = InstrumentationRegistry.getContext(); + mSubject = new UpdateManager(mUpdateEngine, null); + mStreamingUpdate002 = + UpdateConfig.fromJson(readResource(R.raw.update_config_002_stream)); + } + + @Test + public void applyUpdate_appliesPayloadToUpdateEngine() throws Exception { + mockContextStartServiceAnswer(buildMockPayloadSpec()); + mSubject.applyUpdate(mMockContext, mStreamingUpdate002); + + verify(mUpdateEngine).applyPayload( + "file://blah", + 120, + 340, + new String[]{ + "SWITCH_SLOT_ON_REBOOT=0", // ab_config.force_switch_slot = false + "USER_AGENT=" + UpdateManager.HTTP_USER_AGENT + }); + } + + @Test + @UiThreadTest + public void stateIsRunningAndEngineStatusIsIdle_reApplyLastUpdate() throws Throwable { + mockContextStartServiceAnswer(buildMockPayloadSpec()); + // UpdateEngine always returns IDLE status. + when(mUpdateEngine.bind(any(UpdateEngineCallback.class))).thenAnswer(answer -> { + // When UpdateManager is bound to update_engine, it passes + // UpdateEngineCallback as a callback to update_engine. + UpdateEngineCallback callback = answer.getArgument(0); + callback.onStatusUpdate( + UpdateEngine.UpdateStatusConstants.IDLE, + /*engineProgress*/ 0.0f); + return null; + }); + + mSubject.bind(); + mSubject.applyUpdate(mMockContext, mStreamingUpdate002); + mSubject.unbind(); + mSubject.bind(); // re-bind - now it should re-apply last update + + assertEquals(mSubject.getUpdaterState(), UpdaterState.RUNNING); + verify(mUpdateEngine, times(2)).applyPayload( + "file://blah", + 120, + 340, + new String[]{ + "SWITCH_SLOT_ON_REBOOT=0", // ab_config.force_switch_slot = false + "USER_AGENT=" + UpdateManager.HTTP_USER_AGENT + }); + } + + private void mockContextStartServiceAnswer(PayloadSpec payloadSpec) { + doAnswer(args -> { + Intent intent = args.getArgument(0); + ResultReceiver resultReceiver = intent.getParcelableExtra( + PrepareUpdateService.EXTRA_PARAM_RESULT_RECEIVER); + Bundle b = new Bundle(); + b.putSerializable( + /* PrepareUpdateService.CallbackResultReceiver.BUNDLE_PARAM_PAYLOAD_SPEC */ + "payload-spec", + payloadSpec); + resultReceiver.send(PrepareUpdateService.RESULT_CODE_SUCCESS, b); + return null; + }).when(mMockContext).startService(any(Intent.class)); + } + + private PayloadSpec buildMockPayloadSpec() { + PayloadSpec payload = mock(PayloadSpec.class); + when(payload.getUrl()).thenReturn("file://blah"); + when(payload.getOffset()).thenReturn(120L); + when(payload.getSize()).thenReturn(340L); + when(payload.getProperties()).thenReturn(ImmutableList.of()); + return payload; + } + + private String readResource(int id) throws IOException { + return CharStreams.toString(new InputStreamReader( + mTestContext.getResources().openRawResource(id))); + } + +} diff --git a/updater_sample/tests/src/com/example/android/systemupdatersample/util/FileDownloaderTest.java b/updater_sample/tests/src/com/example/android/systemupdatersample/util/FileDownloaderTest.java new file mode 100644 index 000000000..a136ff0ed --- /dev/null +++ b/updater_sample/tests/src/com/example/android/systemupdatersample/util/FileDownloaderTest.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * 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.example.android.systemupdatersample.util; + +import static org.junit.Assert.assertEquals; + +import android.content.Context; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import com.example.android.systemupdatersample.tests.R; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Paths; + +/** + * Tests for {@link FileDownloader} + */ +@RunWith(AndroidJUnit4.class) +@SmallTest +public class FileDownloaderTest { + + @Rule + public final ExpectedException thrown = ExpectedException.none(); + + private Context mTestContext; + private Context mTargetContext; + + @Before + public void setUp() { + mTestContext = InstrumentationRegistry.getContext(); + mTargetContext = InstrumentationRegistry.getTargetContext(); + } + + @Test + public void download_downloadsChunkOfZip() throws Exception { + // Prepare the target file + File packageFile = Paths + .get(mTargetContext.getCacheDir().getAbsolutePath(), "ota.zip") + .toFile(); + Files.deleteIfExists(packageFile.toPath()); + Files.copy(mTestContext.getResources().openRawResource(R.raw.ota_002_package), + packageFile.toPath()); + String url = "file://" + packageFile.getAbsolutePath(); + // prepare where to download + File outFile = Paths + .get(mTargetContext.getCacheDir().getAbsolutePath(), "care_map.txt") + .toFile(); + Files.deleteIfExists(outFile.toPath()); + // download a chunk of ota.zip + FileDownloader downloader = new FileDownloader(url, 1674, 12, outFile); + downloader.download(); + String downloadedContent = String.join("\n", Files.readAllLines(outFile.toPath())); + // archive contains text files with uppercase filenames + assertEquals("CARE_MAP-TXT", downloadedContent); + } + +} diff --git a/updater_sample/tests/src/com/example/android/systemupdatersample/util/PayloadSpecsTest.java b/updater_sample/tests/src/com/example/android/systemupdatersample/util/PayloadSpecsTest.java new file mode 100644 index 000000000..03086930e --- /dev/null +++ b/updater_sample/tests/src/com/example/android/systemupdatersample/util/PayloadSpecsTest.java @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * 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.example.android.systemupdatersample.util; + +import static com.example.android.systemupdatersample.util.PackageFiles.PAYLOAD_BINARY_FILE_NAME; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import android.content.Context; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import com.example.android.systemupdatersample.PayloadSpec; +import com.example.android.systemupdatersample.tests.R; +import com.google.common.base.Charsets; +import com.google.common.io.Files; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Paths; + +/** + * Tests if PayloadSpecs parses update package zip file correctly. + */ +@RunWith(AndroidJUnit4.class) +@SmallTest +public class PayloadSpecsTest { + + private static final String PROPERTIES_CONTENTS = "k1=val1\nkey2=val2"; + + private File mTestDir; + + private Context mTargetContext; + private Context mTestContext; + + private PayloadSpecs mPayloadSpecs; + + @Rule + public final ExpectedException thrown = ExpectedException.none(); + + @Before + public void setUp() { + mTargetContext = InstrumentationRegistry.getTargetContext(); + mTestContext = InstrumentationRegistry.getContext(); + + mTestDir = mTargetContext.getCacheDir(); + mPayloadSpecs = new PayloadSpecs(); + } + + @Test + public void forNonStreaming_works() throws Exception { + // Prepare the target file + File packageFile = Paths + .get(mTargetContext.getCacheDir().getAbsolutePath(), "ota.zip") + .toFile(); + java.nio.file.Files.deleteIfExists(packageFile.toPath()); + java.nio.file.Files.copy(mTestContext.getResources().openRawResource(R.raw.ota_002_package), + packageFile.toPath()); + PayloadSpec spec = mPayloadSpecs.forNonStreaming(packageFile); + + assertEquals("correct url", "file://" + packageFile.getAbsolutePath(), spec.getUrl()); + assertEquals("correct payload offset", + 30 + PAYLOAD_BINARY_FILE_NAME.length(), spec.getOffset()); + assertEquals("correct payload size", 1392, spec.getSize()); + assertEquals(4, spec.getProperties().size()); + assertEquals( + "FILE_HASH=sEAK/NMbU7GGe01xt55FsPafIPk8IYyBOAd6SiDpiMs=", + spec.getProperties().get(0)); + } + + @Test + public void forNonStreaming_IOException() throws Exception { + thrown.expect(IOException.class); + mPayloadSpecs.forNonStreaming(new File("/fake/news.zip")); + } + + @Test + public void forStreaming_works() throws Exception { + String url = "http://a.com/b.zip"; + long offset = 45; + long size = 200; + File propertiesFile = createMockPropertiesFile(); + + PayloadSpec spec = mPayloadSpecs.forStreaming(url, offset, size, propertiesFile); + assertEquals("same url", url, spec.getUrl()); + assertEquals("same offset", offset, spec.getOffset()); + assertEquals("same size", size, spec.getSize()); + assertArrayEquals("correct properties", + new String[]{"k1=val1", "key2=val2"}, spec.getProperties().toArray(new String[0])); + } + + private File createMockPropertiesFile() throws IOException { + File propertiesFile = new File(mTestDir, PackageFiles.PAYLOAD_PROPERTIES_FILE_NAME); + Files.asCharSink(propertiesFile, Charsets.UTF_8).write(PROPERTIES_CONTENTS); + return propertiesFile; + } + +} diff --git a/updater_sample/tests/src/com/example/android/systemupdatersample/util/UpdateConfigsTest.java b/updater_sample/tests/src/com/example/android/systemupdatersample/util/UpdateConfigsTest.java new file mode 100644 index 000000000..4ccae9380 --- /dev/null +++ b/updater_sample/tests/src/com/example/android/systemupdatersample/util/UpdateConfigsTest.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * 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.example.android.systemupdatersample.util; + +import static org.junit.Assert.assertArrayEquals; + +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import com.example.android.systemupdatersample.UpdateConfig; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; + +import java.util.Arrays; +import java.util.List; + +/** + * Tests for {@link UpdateConfigs} + */ +@RunWith(AndroidJUnit4.class) +@SmallTest +public class UpdateConfigsTest { + + @Rule + public final ExpectedException thrown = ExpectedException.none(); + + @Test + public void configsToNames_extractsNames() { + List<UpdateConfig> configs = Arrays.asList( + new UpdateConfig("blah", "http://", UpdateConfig.AB_INSTALL_TYPE_NON_STREAMING), + new UpdateConfig("blah 2", "http://", UpdateConfig.AB_INSTALL_TYPE_STREAMING) + ); + String[] names = UpdateConfigs.configsToNames(configs); + assertArrayEquals(new String[] {"blah", "blah 2"}, names); + } +} |