1 /*
2  * Copyright (C) 2023 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.android.tradefed.targetprep;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import static org.junit.Assert.assertThrows;
22 import static org.mockito.ArgumentMatchers.any;
23 import static org.mockito.ArgumentMatchers.anyList;
24 import static org.mockito.ArgumentMatchers.anyString;
25 import static org.mockito.ArgumentMatchers.eq;
26 import static org.mockito.Mockito.doThrow;
27 import static org.mockito.Mockito.never;
28 import static org.mockito.Mockito.verify;
29 import static org.mockito.Mockito.when;
30 
31 import com.android.tradefed.config.OptionSetter;
32 import com.android.tradefed.device.ITestDevice;
33 import com.android.tradefed.invoker.IInvocationContext;
34 import com.android.tradefed.invoker.InvocationContext;
35 import com.android.tradefed.invoker.TestInformation;
36 import com.android.tradefed.log.ITestLogger;
37 import com.android.tradefed.result.error.DeviceErrorIdentifier;
38 import com.android.tradefed.result.error.InfraErrorIdentifier;
39 import com.android.tradefed.util.CommandResult;
40 import com.android.tradefed.util.CommandStatus;
41 import com.android.tradefed.util.DeviceActionUtil;
42 
43 import com.google.common.collect.ImmutableList;
44 
45 import org.junit.Before;
46 import org.junit.Rule;
47 import org.junit.Test;
48 import org.junit.rules.TemporaryFolder;
49 import org.junit.runner.RunWith;
50 import org.junit.runners.JUnit4;
51 import org.mockito.ArgumentCaptor;
52 import org.mockito.Mock;
53 import org.mockito.junit.MockitoJUnit;
54 import org.mockito.junit.MockitoRule;
55 
56 import java.io.File;
57 import java.io.IOException;
58 import java.util.List;
59 
60 @RunWith(JUnit4.class)
61 public final class DeviceActionTargetPreparerTest {
62 
63     private static final String SERIAL = "serial";
64 
65     @Rule public final MockitoRule mockito = MockitoJUnit.rule();
66     @Rule public TemporaryFolder tempFolder = new TemporaryFolder();
67 
68     @Mock DeviceActionUtil mockDeviceActionUtil;
69     @Mock ITestLogger mockTestLogger;
70     @Mock ITestDevice mockDevice;
71     @Mock CommandResult mCommandResult;
72 
73     private OptionSetter mSetter;
74     private TestInformation mTestInfo;
75     private DeviceActionTargetPreparer mDeviceActionTargetPreparer;
76 
77     @Before
setUp()78     public void setUp() throws Exception {
79         File deviceActionJar = tempFolder.newFile("DeviceActionMainline_deploy.jar");
80         File bundletoolJar = tempFolder.newFile("bundletool.jar");
81         IInvocationContext context = new InvocationContext();
82         context.addAllocatedDevice(SERIAL, mockDevice);
83         mTestInfo = TestInformation.newBuilder().setInvocationContext(context).build();
84         when(mockDevice.getSerialNumber()).thenReturn(SERIAL);
85         when(mockDeviceActionUtil.execute(any(), anyString(), anyList()))
86                 .thenReturn(mCommandResult);
87         when(mCommandResult.getStderr()).thenReturn("");
88         when(mCommandResult.getStdout()).thenReturn("");
89         when(mCommandResult.getStatus()).thenReturn(CommandStatus.SUCCESS);
90         when(mCommandResult.getExitCode()).thenReturn(0);
91         mDeviceActionTargetPreparer = new DeviceActionTargetPreparer();
92         mSetter = new OptionSetter(mDeviceActionTargetPreparer);
93         mSetter.setOptionValue("bundletool-jar", bundletoolJar.getAbsolutePath());
94         mSetter.setOptionValue("device-action-jar", deviceActionJar.getAbsolutePath());
95         mDeviceActionTargetPreparer.setDeviceActionUtil(mockDeviceActionUtil);
96         mDeviceActionTargetPreparer.setTestLogger(mockTestLogger);
97     }
98 
99     @Test
setUp_resetSuccess()100     public void setUp_resetSuccess() throws Exception {
101         mSetter.setOptionValue("da-command", "RESET");
102 
103         mDeviceActionTargetPreparer.setUp(mTestInfo);
104 
105         verify(mockDeviceActionUtil)
106                 .execute(DeviceActionUtil.Command.RESET, SERIAL, ImmutableList.of());
107     }
108 
109     @Test
setUp_installMainlineModules()110     public void setUp_installMainlineModules() throws Exception {
111         File apk1 = new File("apk1");
112         File apk2 = new File("apk2");
113         mSetter.setOptionValue("da-command", "INSTALL_MAINLINE");
114         mSetter.setOptionValue("enable-rollback", "false");
115         mSetter.setOptionValue("mainline-modules", apk1.getAbsolutePath());
116         mSetter.setOptionValue("mainline-modules", apk2.getAbsolutePath());
117 
118         mDeviceActionTargetPreparer.setUp(mTestInfo);
119 
120         ArgumentCaptor<List> argCaptor = ArgumentCaptor.forClass(List.class);
121         verify(mockDeviceActionUtil)
122                 .execute(
123                         eq(DeviceActionUtil.Command.INSTALL_MAINLINE),
124                         eq(SERIAL),
125                         argCaptor.capture());
126         List<String> args = argCaptor.getValue();
127         assertThat(args).hasSize(1);
128         assertThat(args)
129                 .containsAnyOf(
130                         String.format(
131                                 "file_mainline_modules=%s, file_mainline_modules=%s",
132                                 apk1.getAbsolutePath(), apk2.getAbsolutePath()),
133                         String.format(
134                                 "file_mainline_modules=%s, file_mainline_modules=%s",
135                                 apk2.getAbsolutePath(), apk1.getAbsolutePath()));
136     }
137 
138     @Test
setUp_installApksZips()139     public void setUp_installApksZips() throws Exception {
140         File zip1 = new File("zip1");
141         File zip2 = new File("zip2");
142         mSetter.setOptionValue("da-command", "INSTALL_MAINLINE");
143         mSetter.setOptionValue("enable-rollback", "true");
144         mSetter.setOptionValue("apks-zips", zip1.getAbsolutePath());
145         mSetter.setOptionValue("apks-zips", zip2.getAbsolutePath());
146 
147         mDeviceActionTargetPreparer.setUp(mTestInfo);
148 
149         ArgumentCaptor<List> argCaptor = ArgumentCaptor.forClass(List.class);
150         verify(mockDeviceActionUtil)
151                 .execute(
152                         eq(DeviceActionUtil.Command.INSTALL_MAINLINE),
153                         eq(SERIAL),
154                         argCaptor.capture());
155         List<String> args = argCaptor.getValue();
156         assertThat(args).hasSize(2);
157         assertThat(args).contains("enable_rollback");
158         assertThat(args)
159                 .containsAnyOf(
160                         String.format(
161                                 "file_apks_zips=%s, file_apks_zips=%s",
162                                 zip1.getAbsolutePath(), zip2.getAbsolutePath()),
163                         String.format(
164                                 "file_apks_zips=%s, file_apks_zips=%s",
165                                 zip2.getAbsolutePath(), zip1.getAbsolutePath()));
166     }
167 
168     @Test
setUp_installTrainFolder()169     public void setUp_installTrainFolder() throws Exception {
170         File trainFolder = tempFolder.newFolder("train");
171         mSetter.setOptionValue("da-command", "INSTALL_MAINLINE");
172         mSetter.setOptionValue("dev-key-signed", "true");
173         mSetter.setOptionValue("train-folder", trainFolder.getAbsolutePath());
174 
175         mDeviceActionTargetPreparer.setUp(mTestInfo);
176 
177         verify(mockDeviceActionUtil)
178                 .execute(
179                         DeviceActionUtil.Command.INSTALL_MAINLINE,
180                         SERIAL,
181                         ImmutableList.of(
182                                 String.format(
183                                         "file_train_folder=%s", trainFolder.getAbsolutePath()),
184                                 "enable_rollback",
185                                 "dev_key_signed"));
186     }
187 
188     @Test
setUp_doNothingIfNoModuleToInstall()189     public void setUp_doNothingIfNoModuleToInstall() throws Exception {
190         mSetter.setOptionValue("da-command", "INSTALL_MAINLINE");
191 
192         mDeviceActionTargetPreparer.setUp(mTestInfo);
193 
194         verify(mockDeviceActionUtil, never())
195                 .execute(any(DeviceActionUtil.Command.class), anyString(), anyList());
196     }
197 
198     @Test
setUp_executeFailureThrowExecutionException()199     public void setUp_executeFailureThrowExecutionException() throws Exception {
200         mSetter.setOptionValue("da-command", "RESET");
201         when(mCommandResult.getExitCode()).thenReturn(1);
202 
203         TargetSetupError t =
204                 assertThrows(
205                         TargetSetupError.class, () -> mDeviceActionTargetPreparer.setUp(mTestInfo));
206 
207         assertThat(t.getErrorId()).isEqualTo(DeviceErrorIdentifier.DEVICE_ACTION_EXECUTION_FAILURE);
208         verify(mockDeviceActionUtil).saveToLogs(DeviceActionUtil.Command.RESET, mockTestLogger);
209     }
210 
211     @Test
setUp_saveLogErrorThrowInfraException()212     public void setUp_saveLogErrorThrowInfraException() throws Exception {
213         mSetter.setOptionValue("da-command", "RESET");
214         doThrow(new IOException()).when(mockDeviceActionUtil).generateLogFile(mCommandResult);
215 
216         TargetSetupError t =
217                 assertThrows(
218                         TargetSetupError.class, () -> mDeviceActionTargetPreparer.setUp(mTestInfo));
219 
220         assertThat(t.getErrorId()).isEqualTo(InfraErrorIdentifier.FAIL_TO_CREATE_FILE);
221     }
222 
223     @Test
setUp_saveLogErrorAndExectionFailureThrowExecutionException()224     public void setUp_saveLogErrorAndExectionFailureThrowExecutionException() throws Exception {
225         mSetter.setOptionValue("da-command", "RESET");
226         when(mCommandResult.getExitCode()).thenReturn(1);
227         doThrow(new IOException()).when(mockDeviceActionUtil).generateLogFile(mCommandResult);
228 
229         TargetSetupError t =
230                 assertThrows(
231                         TargetSetupError.class, () -> mDeviceActionTargetPreparer.setUp(mTestInfo));
232 
233         assertThat(t.getErrorId()).isEqualTo(DeviceErrorIdentifier.DEVICE_ACTION_EXECUTION_FAILURE);
234     }
235 }
236