Home | History | Annotate | Download | only in testtype
      1 /*
      2  * Copyright (C) 2016 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.testtype;
     17 
     18 import com.android.tradefed.build.IBuildInfo;
     19 import com.android.tradefed.config.ConfigurationException;
     20 import com.android.tradefed.config.Option;
     21 import com.android.tradefed.config.OptionSetter;
     22 import com.android.tradefed.device.ITestDevice;
     23 import com.android.tradefed.log.LogUtil.CLog;
     24 
     25 import junit.framework.Test;
     26 import junit.framework.TestSuite;
     27 
     28 import org.junit.internal.runners.JUnit38ClassRunner;
     29 import org.junit.runner.Runner;
     30 import org.junit.runner.notification.RunNotifier;
     31 import org.junit.runners.Suite;
     32 import org.junit.runners.model.InitializationError;
     33 import org.junit.runners.model.RunnerBuilder;
     34 
     35 import java.lang.reflect.InvocationTargetException;
     36 import java.lang.reflect.Method;
     37 import java.util.Enumeration;
     38 import java.util.HashSet;
     39 import java.util.Set;
     40 
     41 /**
     42  * Extends the JUnit4 container {@link Suite} in order to provide a {@link ITestDevice} to the tests
     43  * that requires it.
     44  */
     45 public class DeviceSuite extends Suite
     46         implements IDeviceTest, IBuildReceiver, IAbiReceiver, ISetOptionReceiver {
     47     private ITestDevice mDevice;
     48     private IBuildInfo mBuildInfo;
     49     private IAbi mAbi;
     50 
     51     @Option(name = HostTest.SET_OPTION_NAME, description = HostTest.SET_OPTION_DESC)
     52     private Set<String> mKeyValueOptions = new HashSet<>();
     53 
     54     public DeviceSuite(Class<?> klass, RunnerBuilder builder) throws InitializationError {
     55         super(klass, builder);
     56     }
     57 
     58     @Override
     59     public void setDevice(ITestDevice device) {
     60         mDevice = device;
     61         for (Runner r : getChildren()) {
     62             // propagate to runner if it needs a device.
     63             if (r instanceof IDeviceTest) {
     64                 if (mDevice == null) {
     65                     throw new IllegalArgumentException("Missing device");
     66                 }
     67                 ((IDeviceTest)r).setDevice(mDevice);
     68             }
     69         }
     70     }
     71 
     72     @Override
     73     public ITestDevice getDevice() {
     74         return mDevice;
     75     }
     76 
     77     @Override
     78     public void setAbi(IAbi abi) {
     79         mAbi = abi;
     80         for (Runner r : getChildren()) {
     81             // propagate to runner if it needs an abi.
     82             if (r instanceof IAbiReceiver) {
     83                 ((IAbiReceiver)r).setAbi(mAbi);
     84             }
     85         }
     86     }
     87 
     88     @Override
     89     public IAbi getAbi() {
     90         return mAbi;
     91     }
     92 
     93     @Override
     94     public void setBuild(IBuildInfo buildInfo) {
     95         mBuildInfo = buildInfo;
     96         for (Runner r : getChildren()) {
     97             // propagate to runner if it needs a buildInfo.
     98             if (r instanceof IBuildReceiver) {
     99                 if (mBuildInfo == null) {
    100                     throw new IllegalArgumentException("Missing build information");
    101                 }
    102                 ((IBuildReceiver)r).setBuild(mBuildInfo);
    103             }
    104         }
    105     }
    106 
    107     @Override
    108     protected void runChild(Runner runner, RunNotifier notifier) {
    109         // Handle legacy JUnit3 style
    110         if (runner instanceof JUnit38ClassRunner) {
    111             JUnit38ClassRunner junit3Runner = (JUnit38ClassRunner) runner;
    112             try {
    113                 // getTest is private so we use reflection to get the test object.
    114                 Method getTest = junit3Runner.getClass().getDeclaredMethod("getTest");
    115                 getTest.setAccessible(true);
    116                 Test test = (Test) getTest.invoke(junit3Runner);
    117                 if (test instanceof TestSuite) {
    118                     TestSuite testSuite = (TestSuite) test;
    119                     Enumeration<Test> testEnum = testSuite.tests();
    120                     while (testEnum.hasMoreElements()) {
    121                         Test t = testEnum.nextElement();
    122                         injectValues(t);
    123                     }
    124                 } else {
    125                     injectValues(test);
    126                 }
    127             } catch (NoSuchMethodException
    128                     | SecurityException
    129                     | IllegalAccessException
    130                     | IllegalArgumentException
    131                     | InvocationTargetException e) {
    132                 throw new RuntimeException(
    133                         String.format(
    134                                 "Failed to invoke junit3 runner: %s",
    135                                 junit3Runner.getClass().getName()),
    136                         e);
    137             }
    138         }
    139         try {
    140             OptionSetter setter = new OptionSetter(runner);
    141             for (String kv : mKeyValueOptions) {
    142                 setter.setOptionValue(HostTest.SET_OPTION_NAME, kv);
    143             }
    144         } catch (ConfigurationException e) {
    145             CLog.d("Could not set option set-option on '%s', reason: '%s'", runner, e.getMessage());
    146         }
    147         super.runChild(runner, notifier);
    148     }
    149 
    150     /** Inject the options to the tests. */
    151     private void injectValues(Object testObj) {
    152         if (testObj instanceof IDeviceTest) {
    153             if (mDevice == null) {
    154                 throw new IllegalArgumentException("Missing device");
    155             }
    156             ((IDeviceTest) testObj).setDevice(mDevice);
    157         }
    158         if (testObj instanceof IBuildReceiver) {
    159             if (mBuildInfo == null) {
    160                 throw new IllegalArgumentException("Missing build information");
    161             }
    162             ((IBuildReceiver) testObj).setBuild(mBuildInfo);
    163         }
    164         // We are more flexible about abi information since not always available.
    165         if (testObj instanceof IAbiReceiver) {
    166             ((IAbiReceiver) testObj).setAbi(mAbi);
    167         }
    168     }
    169 }
    170