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.sandbox; 17 18 import com.android.tradefed.config.Configuration; 19 import com.android.tradefed.config.IConfiguration; 20 import com.android.tradefed.invoker.IInvocationContext; 21 import com.android.tradefed.log.LogUtil.CLog; 22 import com.android.tradefed.result.ITestInvocationListener; 23 import com.android.tradefed.util.CommandResult; 24 import com.android.tradefed.util.CommandStatus; 25 import com.android.tradefed.util.PrettyPrintDelimiter; 26 import com.android.tradefed.util.SerializationUtil; 27 28 import org.json.JSONException; 29 import org.json.JSONObject; 30 31 import java.io.File; 32 import java.io.IOException; 33 import java.util.regex.Matcher; 34 import java.util.regex.Pattern; 35 36 /** Run the tests associated with the invocation in the sandbox. */ 37 public class SandboxInvocationRunner { 38 39 /** Do setup and run the tests */ prepareAndRun( IConfiguration config, IInvocationContext context, ITestInvocationListener listener)40 public static void prepareAndRun( 41 IConfiguration config, IInvocationContext context, ITestInvocationListener listener) 42 throws Throwable { 43 // TODO: refactor TestInvocation to be more modular in the sandbox handling 44 ISandbox sandbox = 45 (ISandbox) config.getConfigurationObject(Configuration.SANDBOX_TYPE_NAME); 46 if (sandbox == null) { 47 throw new RuntimeException("Couldn't find the sandbox object."); 48 } 49 PrettyPrintDelimiter.printStageDelimiter("Starting Sandbox Environment Setup"); 50 Exception res = sandbox.prepareEnvironment(context, config, listener); 51 if (res != null) { 52 CLog.w("Sandbox prepareEnvironment threw an Exception."); 53 sandbox.tearDown(); 54 throw res; 55 } 56 PrettyPrintDelimiter.printStageDelimiter("Done with Sandbox Environment Setup"); 57 try { 58 CommandResult result = sandbox.run(config, listener); 59 if (!CommandStatus.SUCCESS.equals(result.getStatus())) { 60 handleStderrException(result.getStderr()); 61 } 62 } finally { 63 sandbox.tearDown(); 64 } 65 } 66 67 /** Attempt to extract a proper exception from stderr, if not stick to RuntimeException. */ handleStderrException(String stderr)68 private static void handleStderrException(String stderr) throws Throwable { 69 Pattern pattern = 70 Pattern.compile(String.format(".*%s.*", TradefedSandboxRunner.EXCEPTION_KEY)); 71 for (String line : stderr.split("\n")) { 72 Matcher m = pattern.matcher(line); 73 if (m.matches()) { 74 try { 75 JSONObject json = new JSONObject(line); 76 String filePath = json.getString(TradefedSandboxRunner.EXCEPTION_KEY); 77 File exception = new File(filePath); 78 Throwable obj = (Throwable) SerializationUtil.deserialize(exception, true); 79 throw obj; 80 } catch (JSONException | IOException e) { 81 // ignore 82 CLog.w( 83 "Could not parse the stderr as a particular exception. " 84 + "Using RuntimeException instead."); 85 } 86 } 87 } 88 throw new RuntimeException(stderr); 89 } 90 } 91