1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.example.android.systemupdatersample; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.mockito.ArgumentMatchers.any; 21 import static org.mockito.Mockito.doAnswer; 22 import static org.mockito.Mockito.mock; 23 import static org.mockito.Mockito.times; 24 import static org.mockito.Mockito.verify; 25 import static org.mockito.Mockito.when; 26 27 import android.content.Context; 28 import android.content.Intent; 29 import android.os.Bundle; 30 import android.os.ResultReceiver; 31 import android.os.UpdateEngine; 32 import android.os.UpdateEngineCallback; 33 34 import androidx.test.InstrumentationRegistry; 35 import androidx.test.annotation.UiThreadTest; 36 import androidx.test.filters.SmallTest; 37 import androidx.test.runner.AndroidJUnit4; 38 39 import com.example.android.systemupdatersample.services.PrepareUpdateService; 40 import com.example.android.systemupdatersample.tests.R; 41 import com.google.common.collect.ImmutableList; 42 import com.google.common.io.CharStreams; 43 44 import org.junit.Before; 45 import org.junit.Rule; 46 import org.junit.Test; 47 import org.junit.runner.RunWith; 48 import org.mockito.Mock; 49 import org.mockito.junit.MockitoJUnit; 50 import org.mockito.junit.MockitoRule; 51 52 import java.io.IOException; 53 import java.io.InputStreamReader; 54 55 /** 56 * Tests for {@link UpdateManager} 57 */ 58 @RunWith(AndroidJUnit4.class) 59 @SmallTest 60 public class UpdateManagerTest { 61 62 @Rule 63 public MockitoRule mockito = MockitoJUnit.rule(); 64 65 @Mock 66 private UpdateEngine mUpdateEngine; 67 @Mock 68 private Context mMockContext; 69 private UpdateManager mSubject; 70 private Context mTestContext; 71 private UpdateConfig mStreamingUpdate002; 72 73 @Before setUp()74 public void setUp() throws Exception { 75 mTestContext = InstrumentationRegistry.getContext(); 76 mSubject = new UpdateManager(mUpdateEngine, null); 77 mStreamingUpdate002 = 78 UpdateConfig.fromJson(readResource(R.raw.update_config_002_stream)); 79 } 80 81 @Test applyUpdate_appliesPayloadToUpdateEngine()82 public void applyUpdate_appliesPayloadToUpdateEngine() throws Exception { 83 mockContextStartServiceAnswer(buildMockPayloadSpec()); 84 mSubject.applyUpdate(mMockContext, mStreamingUpdate002); 85 86 verify(mUpdateEngine).applyPayload( 87 "file://blah", 88 120, 89 340, 90 new String[]{ 91 "SWITCH_SLOT_ON_REBOOT=0", // ab_config.force_switch_slot = false 92 "USER_AGENT=" + UpdateManager.HTTP_USER_AGENT 93 }); 94 } 95 96 @Test 97 @UiThreadTest stateIsRunningAndEngineStatusIsIdle_reApplyLastUpdate()98 public void stateIsRunningAndEngineStatusIsIdle_reApplyLastUpdate() throws Throwable { 99 mockContextStartServiceAnswer(buildMockPayloadSpec()); 100 // UpdateEngine always returns IDLE status. 101 when(mUpdateEngine.bind(any(UpdateEngineCallback.class))).thenAnswer(answer -> { 102 // When UpdateManager is bound to update_engine, it passes 103 // UpdateEngineCallback as a callback to update_engine. 104 UpdateEngineCallback callback = answer.getArgument(0); 105 callback.onStatusUpdate( 106 UpdateEngine.UpdateStatusConstants.IDLE, 107 /*engineProgress*/ 0.0f); 108 return null; 109 }); 110 111 mSubject.bind(); 112 mSubject.applyUpdate(mMockContext, mStreamingUpdate002); 113 mSubject.unbind(); 114 mSubject.bind(); // re-bind - now it should re-apply last update 115 116 assertEquals(mSubject.getUpdaterState(), UpdaterState.RUNNING); 117 verify(mUpdateEngine, times(2)).applyPayload( 118 "file://blah", 119 120, 120 340, 121 new String[]{ 122 "SWITCH_SLOT_ON_REBOOT=0", // ab_config.force_switch_slot = false 123 "USER_AGENT=" + UpdateManager.HTTP_USER_AGENT 124 }); 125 } 126 mockContextStartServiceAnswer(PayloadSpec payloadSpec)127 private void mockContextStartServiceAnswer(PayloadSpec payloadSpec) { 128 doAnswer(args -> { 129 Intent intent = args.getArgument(0); 130 ResultReceiver resultReceiver = intent.getParcelableExtra( 131 PrepareUpdateService.EXTRA_PARAM_RESULT_RECEIVER); 132 Bundle b = new Bundle(); 133 b.putSerializable( 134 /* PrepareUpdateService.CallbackResultReceiver.BUNDLE_PARAM_PAYLOAD_SPEC */ 135 "payload-spec", 136 payloadSpec); 137 resultReceiver.send(PrepareUpdateService.RESULT_CODE_SUCCESS, b); 138 return null; 139 }).when(mMockContext).startService(any(Intent.class)); 140 } 141 buildMockPayloadSpec()142 private PayloadSpec buildMockPayloadSpec() { 143 PayloadSpec payload = mock(PayloadSpec.class); 144 when(payload.getUrl()).thenReturn("file://blah"); 145 when(payload.getOffset()).thenReturn(120L); 146 when(payload.getSize()).thenReturn(340L); 147 when(payload.getProperties()).thenReturn(ImmutableList.of()); 148 return payload; 149 } 150 readResource(int id)151 private String readResource(int id) throws IOException { 152 return CharStreams.toString(new InputStreamReader( 153 mTestContext.getResources().openRawResource(id))); 154 } 155 156 } 157