blob: fc9e186eedb85377eae4196dc0d76f6e9d8bf37b [file] [log] [blame]
/*
* Copyright (C) 2020 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.android.tradefed.cluster;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import com.android.tradefed.config.Configuration;
import com.android.tradefed.config.ConfigurationException;
import com.android.tradefed.config.IConfiguration;
import com.android.tradefed.config.IDeviceConfiguration;
import com.android.tradefed.result.ITestInvocationListener;
import com.android.tradefed.result.TextResultReporter;
import com.android.tradefed.targetprep.ITargetPreparer;
import com.android.tradefed.targetprep.StubTargetPreparer;
import com.android.tradefed.util.FileUtil;
import com.android.tradefed.util.MultiMap;
import org.json.JSONException;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.Answers;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/** Unit tests for {@link ClusterCommandConfigBuilder}. */
@RunWith(JUnit4.class)
public class ClusterCommandConfigBuilderTest {
private static final String REQUEST_ID = "request_id";
private static final String COMMAND_ID = "command_id";
private static final String TASK_ID = "task_id";
private static final String COMMAND_LINE = "command_line";
private static final String ATTEMPT_ID = "attempt_id";
private static final String DEVICE_SERIAL = "serial";
@Rule public final MockitoRule mockito = MockitoJUnit.rule();
private File mWorkDir;
private ClusterCommand mCommand;
private TestEnvironment mTestEnvironment;
private List<TestResource> mTestResources;
private TestContext mTestContext;
private Map<String, String> mSystemEnvMap;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private IConfiguration mConfig;
private ClusterCommandConfigBuilder builder;
@Captor private ArgumentCaptor<List<IDeviceConfiguration>> captor;
@Before
public void setUp() throws IOException {
mWorkDir = FileUtil.createTempDir(this.getClass().getSimpleName());
mCommand =
new ClusterCommand(
REQUEST_ID,
COMMAND_ID,
TASK_ID,
COMMAND_LINE,
ATTEMPT_ID,
ClusterCommand.RequestType.MANAGED,
0,
0);
mCommand.setTargetDeviceSerials(List.of(DEVICE_SERIAL));
mTestEnvironment = new TestEnvironment();
mTestResources = new ArrayList<>();
mTestContext = new TestContext();
mSystemEnvMap = new HashMap<String, String>();
builder =
new ClusterCommandConfigBuilder() {
@Override
IConfiguration initConfiguration() {
return mConfig;
}
@Override
Map<String, String> getSystemEnvMap() {
return mSystemEnvMap;
}
};
builder.setWorkDir(mWorkDir)
.setClusterCommand(mCommand)
.setTestEnvironment(mTestEnvironment)
.setTestResources(mTestResources)
.setTestContext(mTestContext);
}
@After
public void tearDown() {
FileUtil.recursiveDelete(mWorkDir);
}
@Test
public void testBuild_commandProperties()
throws IOException, ConfigurationException, JSONException {
builder.build();
// command properties and work directory were injected
verify(mConfig, times(1)).injectOptionValue("cluster:request-id", REQUEST_ID);
verify(mConfig, times(1)).injectOptionValue("cluster:command-id", COMMAND_ID);
verify(mConfig, times(1)).injectOptionValue("cluster:attempt-id", ATTEMPT_ID);
verify(mConfig, times(1)).injectOptionValue("cluster:command-line", COMMAND_LINE);
verify(mConfig, times(1)).injectOptionValue("cluster:root-dir", mWorkDir.getAbsolutePath());
}
@Test
public void testBuild_targetPreparers()
throws IOException, ConfigurationException, JSONException {
// Configure a StubTargetPreparer with a single option
MultiMap<String, String> options = new MultiMap<>();
options.put("no-test-boolean-option", ""); // will flip value to false
TradefedConfigObject preparerConfig =
new TradefedConfigObject(
TradefedConfigObject.Type.TARGET_PREPARER,
StubTargetPreparer.class.getName(),
options);
mTestEnvironment.addTradefedConfigObject(preparerConfig);
builder.build();
// StubTargetPreparer was added to the device configuration
verify(mConfig, times(1)).setDeviceConfigList(captor.capture());
List<ITargetPreparer> preparers = captor.getValue().get(0).getTargetPreparers();
assertEquals(1, preparers.size());
assertThat(preparers.get(0), instanceOf(StubTargetPreparer.class));
assertFalse(((StubTargetPreparer) preparers.get(0)).getTestBooleanOption());
}
@Test
public void testBuild_resultReporters()
throws IOException, ConfigurationException, JSONException {
// Configure a TextResultReporter
TradefedConfigObject reporterConfig =
new TradefedConfigObject(
TradefedConfigObject.Type.RESULT_REPORTER,
TextResultReporter.class.getName(),
new MultiMap<>());
mTestEnvironment.addTradefedConfigObject(reporterConfig);
// Keep track of result reporters
List<ITestInvocationListener> reporters = new ArrayList<>();
doReturn(reporters)
.when(mConfig)
.getConfigurationObjectList(Configuration.RESULT_REPORTER_TYPE_NAME);
builder.build();
// TextResultReporter was added to the configuration
assertEquals(1, reporters.size());
assertThat(reporters.get(0), instanceOf(TextResultReporter.class));
}
@Test
public void testBuild_envVars() throws IOException, ConfigurationException, JSONException {
mTestEnvironment.addEnvVar("E1", "V1");
mTestContext.addEnvVars(Map.of("E2", "V2"));
builder.build();
// work directory and environment variables from both sources were injected
verify(mConfig, times(1))
.injectOptionValue("cluster:env-var", "TF_WORK_DIR", mWorkDir.getAbsolutePath());
verify(mConfig, times(1)).injectOptionValue("cluster:env-var", "TF_ATTEMPT_ID", ATTEMPT_ID);
verify(mConfig, times(1)).injectOptionValue("cluster:env-var", "E1", "V1");
verify(mConfig, times(1)).injectOptionValue("cluster:env-var", "E2", "V2");
}
@Test
public void testBuild_javaOptions() throws IOException, ConfigurationException, JSONException {
mTestEnvironment.addJvmOption("jvm_option");
mTestEnvironment.addJavaProperty("java_property", "java_value");
builder.build();
// JVM options and java properties were injected
verify(mConfig, times(1)).injectOptionValue("cluster:jvm-option", "jvm_option");
verify(mConfig, times(1))
.injectOptionValue("cluster:java-property", "java_property", "java_value");
}
@Test
public void testBuild_outputFiles() throws IOException, ConfigurationException, JSONException {
mTestEnvironment.setOutputFileUploadUrl("base_url");
mTestEnvironment.addOutputFilePattern("pattern");
builder.build();
// output URL was generated and output file patterns were injected
verify(mConfig, times(1))
.injectOptionValue(
"cluster:output-file-upload-url", "base_url/command_id/attempt_id/");
verify(mConfig, times(1)).injectOptionValue("cluster:output-file-pattern", "pattern");
}
@Test
public void testBuild_timeouts() throws IOException, ConfigurationException, JSONException {
mTestEnvironment.setInvocationTimeout(12345);
mTestEnvironment.setOutputIdleTimeout(1234);
builder.build();
// JVM options and java properties were injected
verify(mConfig.getCommandOptions(), times(1)).setInvocationTimeout(12345L);
verify(mConfig, times(1)).injectOptionValue("cluster:output-idle-timeout", "1234");
}
@Test
public void testBuild_testResources()
throws IOException, ConfigurationException, JSONException {
mTestResources.add(new TestResource("N1", "U1", true, "D1", false, Arrays.asList("F1")));
mTestContext.addTestResource(new TestResource("N2", "U2"));
builder.build();
// test resources from both sources were injected
verify(mConfig, times(1))
.injectOptionValue(
"cluster:test-resource", mTestResources.get(0).toJson().toString());
verify(mConfig, times(1))
.injectOptionValue(
"cluster:test-resource",
mTestContext.getTestResources().get(0).toJson().toString());
}
@Test
public void testBuild_testResourcesWithTemplatedUrl()
throws IOException, ConfigurationException, JSONException {
mSystemEnvMap.put("TEMPLATED_URL", "localhost:8000");
mTestResources.add(new TestResource("N1", "${TEMPLATED_URL}/tests"));
TestResource updatedTestResource = new TestResource("N1", "localhost:8000/tests");
builder.build();
verify(mConfig, times(1))
.injectOptionValue(
"cluster:test-resource", updatedTestResource.toJson().toString());
}
@Test
public void testBuild_extraOptions() throws IOException, ConfigurationException, JSONException {
mCommand.getExtraOptions().put("key", "hello");
mCommand.getExtraOptions().put("key", "${E1}");
mTestEnvironment.addEnvVar("E1", "world");
builder.build();
// extra options with same key were injected
verify(mConfig, times(1)).injectOptionValue("key", "hello");
verify(mConfig, times(1)).injectOptionValue("key", "world");
}
@Test
public void testBuild_useParallelSetup()
throws IOException, ConfigurationException, JSONException {
mTestEnvironment.setUseParallelSetup(true);
builder.build();
verify(mConfig, times(1)).injectOptionValue("parallel-setup", "true");
verify(mConfig, times(1)).injectOptionValue("parallel-setup-timeout", "0");
reset(mConfig);
mTestEnvironment.setUseParallelSetup(false);
builder.build();
verify(mConfig, never()).injectOptionValue("parallel-setup", "true");
verify(mConfig, never()).injectOptionValue("parallel-setup-timeout", "0");
}
@Test
public void testBuild_excludedFilesInClasspath()
throws IOException, ConfigurationException, JSONException {
mTestEnvironment.addExcludedFileInJavaClasspath("art-run-test.*");
builder.build();
verify(mConfig, times(1))
.injectOptionValue("cluster:exclude-file-in-java-classpath", "art-run-test.*");
}
}