1 /* 2 * Copyright (C) 2020 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.logger; 17 18 import static com.google.common.truth.Truth.assertThat; 19 20 import org.junit.Test; 21 import org.junit.runner.RunWith; 22 import org.junit.runners.JUnit4; 23 24 import com.google.common.collect.ImmutableSet; 25 import com.google.common.util.concurrent.Futures; 26 27 import java.util.concurrent.Callable; 28 import java.util.concurrent.ExecutorService; 29 import java.util.concurrent.Executors; 30 import java.util.concurrent.Future; 31 import java.util.concurrent.atomic.AtomicInteger; 32 33 /** Unit tests for {@link InvocationLocal}. */ 34 @RunWith(JUnit4.class) 35 public final class InvocationLocalTest { 36 37 private final AtomicInteger nextInvocationId = new AtomicInteger(); 38 39 @Test getInitialValueDefaultsToNull()40 public void getInitialValueDefaultsToNull() { 41 InvocationLocal<Integer> local = new InvocationLocal<>(); 42 43 Object actual = invocation(() -> local.get()); 44 45 assertThat(actual).isNull(); 46 } 47 48 @Test getReturnsCustomInitialValue()49 public void getReturnsCustomInitialValue() { 50 String expected = "!"; 51 InvocationLocal<String> local = 52 new InvocationLocal<String>() { 53 @Override 54 protected String initialValue() { 55 return expected; 56 } 57 }; 58 59 String actual = invocation(() -> local.get()); 60 61 assertThat(actual).isEqualTo(expected); 62 } 63 64 @Test getReturnsSameInitialValue()65 public void getReturnsSameInitialValue() { 66 InvocationLocal<Object> local = 67 new InvocationLocal<Object>() { 68 @Override 69 protected Object initialValue() { 70 return new Object(); 71 } 72 }; 73 74 ImmutableSet<Object> values = invocation(() -> ImmutableSet.of(local.get(), local.get())); 75 76 assertThat(values).hasSize(1); 77 } 78 79 @Test getReturnsDifferentValuePerInvocation()80 public void getReturnsDifferentValuePerInvocation() throws Exception { 81 InvocationLocal<Object> local = 82 new InvocationLocal<Object>() { 83 @Override 84 protected Object initialValue() { 85 return new Object(); 86 } 87 }; 88 89 Object value0 = invocation(() -> local.get()); 90 Object value1 = invocation(() -> local.get()); 91 92 assertThat(value0).isNotSameAs(value1); 93 } 94 95 /** 96 * Runs code in the context of a ThreadGroup to simulate a Tradefed invocation and avoid 97 * interfering with the currently executing test invocation. 98 */ invocation(Callable<T> callable)99 private <T> T invocation(Callable<T> callable) { 100 // TradeFed Invocations are identified by their ThreadGroup. 101 String name = "invocation" + nextInvocationId.getAndIncrement(); 102 ExecutorService executor = 103 Executors.newSingleThreadExecutor(r -> new Thread(new ThreadGroup(name), r)); 104 Future<T> future = 105 executor.submit( 106 () -> { 107 try { 108 return callable.call(); 109 } finally { 110 CurrentInvocation.clearInvocationInfos(); 111 } 112 }); 113 executor.shutdown(); 114 return Futures.getUnchecked(future); 115 } 116 } 117