1 /*
2  * Copyright (C) 2018 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.device.metric;
17 
18 import static org.junit.Assert.assertEquals;
19 import static org.mockito.Mockito.mock;
20 
21 import com.android.tradefed.device.ITestDevice;
22 import com.android.tradefed.invoker.IInvocationContext;
23 import com.android.tradefed.invoker.InvocationContext;
24 import com.android.tradefed.metrics.proto.MetricMeasurement.Measurements;
25 import com.android.tradefed.metrics.proto.MetricMeasurement.Metric;
26 
27 import org.junit.Before;
28 import org.junit.Test;
29 import org.junit.runner.RunWith;
30 import org.junit.runners.JUnit4;
31 
32 import java.util.Collections;
33 import java.util.HashMap;
34 import java.util.List;
35 import java.util.UUID;
36 import java.util.concurrent.Callable;
37 import java.util.concurrent.ExecutionException;
38 import java.util.concurrent.ExecutorService;
39 import java.util.concurrent.Executors;
40 import java.util.concurrent.Future;
41 
42 /** Functional tests for {@link DeviceMetricData} * */
43 @RunWith(JUnit4.class)
44 public class DeviceMetricDataFuncTest {
45 
46     private IInvocationContext mContext;
47 
48     @Before
setUp()49     public void setUp() {
50         mContext = new InvocationContext();
51         ITestDevice device = mock(ITestDevice.class);
52         mContext.addAllocatedDevice("device1", device);
53     }
54 
55     @Test
testAddToMetricsMultiThreaded_success()56     public void testAddToMetricsMultiThreaded_success()
57             throws InterruptedException, ExecutionException {
58         // Incrementing threadCounts in steps and then testing makes sure that there is no
59         // flakyness, sticking to one value of threadCount will cause flakyness.
60         for (int threadCount = 10; threadCount <= 200; threadCount += 10) {
61             testAddToMetricsMultiThreaded(threadCount);
62         }
63     }
64 
testAddToMetricsMultiThreaded(int threadCount)65     private void testAddToMetricsMultiThreaded(int threadCount)
66             throws InterruptedException, ExecutionException {
67         // Create the object to test.
68         DeviceMetricData deviceMetricData = new DeviceMetricData(mContext);
69 
70         // Create a callable wrapper of DeviceMetricData#addStringMetric and
71         // DeviceMetricData#addToMetrics which will add a metric and then try to retrieve it.
72         Callable<HashMap<String, Metric>> task =
73                 new Callable<HashMap<String, Metric>>() {
74 
75                     @Override
76                     public HashMap<String, Metric> call() throws Exception {
77                         deviceMetricData.addMetric(
78                                 UUID.randomUUID().toString(),
79                                 Metric.newBuilder()
80                                         .setMeasurements(
81                                                 Measurements.newBuilder()
82                                                         .setSingleString("value")
83                                                         .build()));
84                         HashMap<String, Metric> data = new HashMap<>();
85                         deviceMetricData.addToMetrics(data);
86                         return data;
87                     }
88                 };
89         // Create a copy of this callable for every thread.
90         List<Callable<HashMap<String, Metric>>> tasks = Collections.nCopies(threadCount, task);
91 
92         // Create a thread pool to execute the tasks.
93         ExecutorService executorService = Executors.newFixedThreadPool(threadCount);
94 
95         // Invoke the tasks. The call to ExecutorService#invokeAll blocks until all the threads are
96         // done.
97         List<Future<HashMap<String, Metric>>> futures = executorService.invokeAll(tasks);
98 
99         // Store the results from all the tasks in a common data structure.
100         HashMap<String, Metric> metricsData = new HashMap<String, Metric>(futures.size());
101         for (Future<HashMap<String, Metric>> future : futures) {
102             metricsData.putAll(future.get());
103         }
104 
105         // assert that the number of metrics out is equal to number of metrics in.
106         assertEquals(threadCount, metricsData.size());
107 
108         // discard all the threads.
109         executorService.shutdownNow();
110     }
111 }
112