1 /* 2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 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 * A copy of the License is located at 7 * 8 * http://aws.amazon.com/apache2.0 9 * 10 * or in the "license" file accompanying this file. This file is distributed 11 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 * express or implied. See the License for the specific language governing 13 * permissions and limitations under the License. 14 */ 15 16 package utils.resources; 17 18 import java.util.HashSet; 19 import java.util.Set; 20 import org.junit.jupiter.api.Disabled; 21 import org.junit.runner.Description; 22 import org.junit.runner.notification.Failure; 23 import org.junit.runner.notification.RunNotifier; 24 import org.junit.runners.BlockJUnit4ClassRunner; 25 import org.junit.runners.model.FrameworkMethod; 26 import org.junit.runners.model.InitializationError; 27 import org.junit.runners.model.Statement; 28 import org.slf4j.Logger; 29 import org.slf4j.LoggerFactory; 30 import utils.resources.RequiredResources.RequiredResource; 31 import utils.resources.RequiredResources.ResourceRetentionPolicy; 32 33 public class ResourceCentricBlockJUnit4ClassRunner extends BlockJUnit4ClassRunner { 34 35 private final Set<TestResource> resourcesToBeDestroyedAfterAllTests; 36 37 private final RequiredResources classRequiredResourcesAnnotation; 38 39 private final Logger log = LoggerFactory.getLogger(ResourceCentricBlockJUnit4ClassRunner.class); 40 ResourceCentricBlockJUnit4ClassRunner(Class<?> klass)41 public ResourceCentricBlockJUnit4ClassRunner(Class<?> klass) 42 throws InitializationError { 43 super(klass); 44 45 classRequiredResourcesAnnotation = klass.getAnnotation(RequiredResources.class); 46 resourcesToBeDestroyedAfterAllTests = new HashSet<TestResource>(); 47 } 48 49 /** 50 * 51 */ createResourceInstance(RequiredResource resourceAnnotation)52 private static TestResource createResourceInstance(RequiredResource resourceAnnotation) 53 throws InstantiationException, IllegalAccessException { 54 Class<? extends TestResource> resourceClazz = resourceAnnotation.resource(); 55 if (resourceClazz == null) { 56 throw new IllegalArgumentException( 57 "resource parameter is missing for the @RequiredResource annotation."); 58 } 59 return resourceClazz.newInstance(); 60 } 61 62 @Override runChild(final FrameworkMethod method, RunNotifier notifier)63 protected void runChild(final FrameworkMethod method, RunNotifier notifier) { 64 Description description = describeChild(method); 65 if (method.getAnnotation(Disabled.class) != null) { 66 notifier.fireTestIgnored(description); 67 } else { 68 RequiredResources annotation = method.getAnnotation(RequiredResources.class); 69 if (annotation != null) { 70 try { 71 beforeRunLeaf(annotation.value()); 72 } catch (Exception e) { 73 notifier.fireTestFailure(new Failure(description, e)); 74 } 75 76 } 77 78 runLeaf(methodBlock(method), description, notifier); 79 80 if (annotation != null) { 81 try { 82 afterRunLeaf(annotation.value()); 83 } catch (Exception e) { 84 notifier.fireTestFailure(new Failure(description, e)); 85 } 86 } 87 } 88 } 89 90 /** 91 * Override the withBeforeClasses method to inject executing resource 92 * creation between @BeforeClass methods and test methods. 93 */ 94 @Override withBeforeClasses(final Statement statement)95 protected Statement withBeforeClasses(final Statement statement) { 96 Statement withRequiredResourcesCreation = new Statement() { 97 98 @Override 99 public void evaluate() throws Throwable { 100 if (classRequiredResourcesAnnotation != null) { 101 beforeRunClass(classRequiredResourcesAnnotation.value()); 102 } 103 statement.evaluate(); 104 } 105 }; 106 return super.withBeforeClasses(withRequiredResourcesCreation); 107 } 108 109 /** 110 * Override the withAfterClasses method to inject executing resource 111 * creation between test methods and the @AfterClass methods. 112 */ 113 @Override withAfterClasses(final Statement statement)114 protected Statement withAfterClasses(final Statement statement) { 115 Statement withRequiredResourcesDeletion = new Statement() { 116 117 @Override 118 public void evaluate() throws Throwable { 119 statement.evaluate(); 120 afterRunClass(); 121 } 122 }; 123 return super.withAfterClasses(withRequiredResourcesDeletion); 124 } 125 beforeRunClass(RequiredResource[] resourcesAnnotation)126 private void beforeRunClass(RequiredResource[] resourcesAnnotation) 127 throws InstantiationException, IllegalAccessException, InterruptedException { 128 log.debug("Processing @RequiredResources before running the test class..."); 129 for (RequiredResource resourceAnnotation : resourcesAnnotation) { 130 TestResource resource = createResourceInstance(resourceAnnotation); 131 TestResourceUtils.createResource(resource, resourceAnnotation.creationPolicy()); 132 133 if (resourceAnnotation.retentionPolicy() != ResourceRetentionPolicy.KEEP) { 134 resourcesToBeDestroyedAfterAllTests.add(resource); 135 } 136 } 137 } 138 afterRunClass()139 private void afterRunClass() 140 throws InstantiationException, IllegalAccessException, InterruptedException { 141 log.debug("Processing @RequiredResources after running the test class..."); 142 for (TestResource resource : resourcesToBeDestroyedAfterAllTests) { 143 TestResourceUtils.deleteResource(resource); 144 } 145 } 146 beforeRunLeaf(RequiredResource[] resourcesAnnotation)147 private void beforeRunLeaf(RequiredResource[] resourcesAnnotation) 148 throws InstantiationException, IllegalAccessException, InterruptedException { 149 log.debug("Processing @RequiredResources before running the test..."); 150 for (RequiredResource resourceAnnotation : resourcesAnnotation) { 151 TestResource resource = createResourceInstance(resourceAnnotation); 152 TestResourceUtils.createResource(resource, resourceAnnotation.creationPolicy()); 153 154 if (resourceAnnotation.retentionPolicy() == ResourceRetentionPolicy.DESTROY_AFTER_ALL_TESTS) { 155 resourcesToBeDestroyedAfterAllTests.add(resource); 156 } 157 } 158 } 159 afterRunLeaf(RequiredResource[] resourcesAnnotation)160 private void afterRunLeaf(RequiredResource[] resourcesAnnotation) 161 throws InstantiationException, IllegalAccessException, InterruptedException { 162 log.debug("Processing @RequiredResources after running the test..."); 163 for (RequiredResource resourceAnnotation : resourcesAnnotation) { 164 TestResource resource = createResourceInstance(resourceAnnotation); 165 166 if (resourceAnnotation.retentionPolicy() == ResourceRetentionPolicy.DESTROY_IMMEDIATELY) { 167 TestResourceUtils.deleteResource(resource); 168 } 169 } 170 } 171 } 172