1 /*
2  * Copyright (C) 2017 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 package com.android.tradefed.invoker.shard;
17 
18 import com.android.tradefed.build.BuildInfoKey.BuildInfoFileKey;
19 import com.android.tradefed.build.ExistingBuildProvider;
20 import com.android.tradefed.build.IBuildInfo;
21 import com.android.tradefed.build.VersionedFile;
22 import com.android.tradefed.config.ConfigurationException;
23 import com.android.tradefed.config.IConfiguration;
24 import com.android.tradefed.config.IDeviceConfiguration;
25 import com.android.tradefed.invoker.ExecutionFiles;
26 import com.android.tradefed.invoker.ExecutionFiles.FilesKey;
27 import com.android.tradefed.invoker.IInvocationContext;
28 import com.android.tradefed.invoker.TestInformation;
29 import com.android.tradefed.log.LogUtil.CLog;
30 
31 /**
32  * Helper class that handles cloning a build info from the command line. Shard will get the build
33  * info directly by using {@link ExistingBuildProvider} instead of downloading anything.
34  */
35 public class ShardBuildCloner {
36 
37     /**
38      * Helper to set the Sharded configuration build provider to the {@link ExistingBuildProvider}.
39      *
40      * @param fromConfig Original configuration
41      * @param toConfig cloned configuration recreated from the command line.
42      * @param testInfo The {@link TestInformation} of the parent shard
43      */
cloneBuildInfos( IConfiguration fromConfig, IConfiguration toConfig, TestInformation testInfo)44     public static void cloneBuildInfos(
45             IConfiguration fromConfig, IConfiguration toConfig, TestInformation testInfo) {
46         IInvocationContext context = testInfo.getContext();
47         IBuildInfo primaryClone = null;
48         for (String deviceName : context.getDeviceConfigNames()) {
49             IBuildInfo toBuild = context.getBuildInfo(deviceName).clone();
50             if (primaryClone == null) {
51                 primaryClone = toBuild;
52             }
53             try {
54                 IDeviceConfiguration deviceConfig = toConfig.getDeviceConfigByName(deviceName);
55                 if (deviceConfig == null) {
56                     throw new RuntimeException(
57                             String.format(
58                                     "Configuration doesn't have device '%s' while context "
59                                             + "does [%s].",
60                                     deviceName, context.getDeviceConfigNames()));
61                 }
62                 deviceConfig.addSpecificConfig(
63                         new ExistingBuildProvider(
64                                 toBuild,
65                                 fromConfig.getDeviceConfigByName(deviceName).getBuildProvider()));
66             } catch (ConfigurationException e) {
67                 // Should never happen, no action taken
68                 CLog.e(e);
69             }
70         }
71 
72         IBuildInfo primaryBuild = context.getBuildInfos().get(0);
73         // Ensure that files that were shared by IBuildInfo and TestInformation that were cloned
74         // are relinked to the new TestInformation.
75         TestInformation newInfo = TestInformation.createCopyTestInfo(testInfo, context);
76         ExecutionFiles execFiles = newInfo.executionFiles();
77         if (execFiles.get(FilesKey.TESTS_DIRECTORY) != null) {
78             if (execFiles
79                     .get(FilesKey.TESTS_DIRECTORY)
80                     .equals(primaryBuild.getFile(BuildInfoFileKey.TESTDIR_IMAGE))) {
81                 execFiles.put(
82                         FilesKey.TESTS_DIRECTORY,
83                         primaryClone.getFile(BuildInfoFileKey.TESTDIR_IMAGE));
84             }
85         }
86         if (execFiles.get(FilesKey.HOST_TESTS_DIRECTORY) != null) {
87             if (execFiles
88                     .get(FilesKey.HOST_TESTS_DIRECTORY)
89                     .equals(primaryBuild.getFile(BuildInfoFileKey.HOST_LINKED_DIR))) {
90                 execFiles.put(
91                         FilesKey.HOST_TESTS_DIRECTORY,
92                         primaryClone.getFile(BuildInfoFileKey.HOST_LINKED_DIR));
93             }
94         }
95         if (execFiles.get(FilesKey.TARGET_TESTS_DIRECTORY) != null) {
96             if (execFiles
97                     .get(FilesKey.TARGET_TESTS_DIRECTORY)
98                     .equals(primaryBuild.getFile(BuildInfoFileKey.TARGET_LINKED_DIR))) {
99                 execFiles.put(
100                         FilesKey.TARGET_TESTS_DIRECTORY,
101                         primaryClone.getFile(BuildInfoFileKey.TARGET_LINKED_DIR));
102             }
103         }
104         // Link the remaining buildInfo files.
105         for (String key : primaryBuild.getVersionedFileKeys()) {
106             VersionedFile versionedFile = primaryBuild.getVersionedFile(key);
107             if (versionedFile.getFile().equals(execFiles.get(key))) {
108                 execFiles.put(key, primaryClone.getFile(key));
109             }
110         }
111         try {
112             toConfig.setConfigurationObject(ShardHelper.SHARED_TEST_INFORMATION, newInfo);
113         } catch (ConfigurationException e) {
114             // Should never happen, no action taken
115             CLog.e(e);
116         }
117     }
118 }
119