• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 
17 package com.android.tradefed.testtype;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import static org.junit.Assert.fail;
22 import static org.mockito.ArgumentMatchers.any;
23 import static org.mockito.ArgumentMatchers.anyString;
24 import static org.mockito.Mockito.doAnswer;
25 import static org.mockito.Mockito.doReturn;
26 
27 import com.android.tradefed.device.DeviceNotAvailableException;
28 import com.android.tradefed.device.ITestDevice;
29 import com.android.tradefed.result.ITestInvocationListener;
30 import com.android.tradefed.result.InputStreamSource;
31 import com.android.tradefed.result.LogDataType;
32 import com.android.tradefed.util.proto.TfMetricProtoUtil;
33 
34 import com.google.common.base.VerifyException;
35 import com.google.protobuf.ByteString;
36 
37 import org.junit.Before;
38 import org.junit.Rule;
39 import org.junit.Test;
40 import org.junit.rules.TemporaryFolder;
41 import org.junit.runner.RunWith;
42 import org.junit.runners.JUnit4;
43 import org.mockito.Mock;
44 import org.mockito.MockitoAnnotations;
45 
46 import java.io.File;
47 import java.io.FileOutputStream;
48 import java.io.IOException;
49 import java.io.InputStream;
50 import java.io.OutputStream;
51 import java.net.URI;
52 import java.nio.charset.StandardCharsets;
53 import java.nio.file.Files;
54 import java.nio.file.FileSystem;
55 import java.nio.file.FileSystems;
56 import java.nio.file.Path;
57 import java.util.ArrayList;
58 import java.util.HashMap;
59 import java.util.List;
60 import java.util.Map;
61 import java.util.StringJoiner;
62 import java.util.zip.ZipFile;
63 
64 /** Unit tests for {@link NativeCodeCoverageListener}. */
65 @RunWith(JUnit4.class)
66 public class NativeCodeCoverageListenerTest {
67 
68     private static final String RUN_NAME = "SomeTest";
69     private static final int TEST_COUNT = 5;
70     private static final long ELAPSED_TIME = 1000;
71 
72     private static final ByteString COVERAGE_MEASUREMENT =
73             ByteString.copyFromUtf8("Mi estas kovrado mezurado");
74 
75     @Rule public TemporaryFolder folder = new TemporaryFolder();
76 
77     @Mock ITestDevice mMockDevice;
78 
79     LogFileReader mFakeListener = new LogFileReader();
80 
81     /** Object under test. */
82     NativeCodeCoverageListener mCodeCoverageListener;
83 
84     @Before
setUp()85     public void setUp() {
86         MockitoAnnotations.initMocks(this);
87 
88         mCodeCoverageListener = new NativeCodeCoverageListener(mMockDevice, mFakeListener);
89     }
90 
91     @Test
test_logsCoverageZip()92     public void test_logsCoverageZip() throws DeviceNotAvailableException, IOException {
93         // Setup mocks to write the coverage measurement to the file.
94         doReturn(true).when(mMockDevice).enableAdbRoot();
95         doReturn(
96                         new StringJoiner("\n")
97                                 .add("/data/misc/trace/proc/self/cwd/out/path/to/coverage.gcda")
98                                 .add(
99                                         "/data/misc/trace/proc/self/cwd/out/path/to/.hidden/coverage2.gcda")
100                                 .toString())
101                 .when(mMockDevice)
102                 .executeShellCommand(anyString());
103         doAnswer(
104                         inv -> {
105                             File destFile = (File) inv.getArgument(1);
106                             try (OutputStream out = new FileOutputStream(destFile)) {
107                                 // Write the filename as the contents.
108                                 out.write(destFile.getName().getBytes(StandardCharsets.UTF_8));
109                             }
110                             return true;
111                         })
112                 .when(mMockDevice)
113                 .pullFile(anyString(), any());
114 
115         // Simulate a test run.
116         mCodeCoverageListener.testRunStarted(RUN_NAME, TEST_COUNT);
117         Map<String, String> metric = new HashMap<>();
118         mCodeCoverageListener.testRunEnded(ELAPSED_TIME, TfMetricProtoUtil.upgradeConvert(metric));
119 
120         // Verify testLog(..) was called with the coverage file in a zip.
121         List<ByteString> logs = mFakeListener.getLogs();
122         assertThat(logs).hasSize(1);
123         File outputZip = folder.newFile("coverage.zip");
124         try (OutputStream out = new FileOutputStream(outputZip)) {
125             logs.get(0).writeTo(out);
126         }
127 
128         URI uri = URI.create(String.format("jar:file:%s", outputZip));
129         try (FileSystem filesystem = FileSystems.newFileSystem(uri, new HashMap<>())) {
130             Path path1 = filesystem.getPath("/path/to/coverage.gcda");
131             assertThat(ByteString.readFrom(Files.newInputStream(path1)))
132                     .isEqualTo(ByteString.copyFromUtf8("coverage.gcda"));
133 
134             Path path2 = filesystem.getPath("/path/to/.hidden/coverage2.gcda");
135             assertThat(ByteString.readFrom(Files.newInputStream(path2)))
136                     .isEqualTo(ByteString.copyFromUtf8("coverage2.gcda"));
137         }
138     }
139 
140     @Test
testNoCoverageFiles_logsEmptyZip()141     public void testNoCoverageFiles_logsEmptyZip() throws DeviceNotAvailableException, IOException {
142         doReturn(true).when(mMockDevice).enableAdbRoot();
143         doReturn("").when(mMockDevice).executeShellCommand(anyString());
144 
145         // Simulate a test run.
146         mCodeCoverageListener.testRunStarted(RUN_NAME, TEST_COUNT);
147         Map<String, String> metric = new HashMap<>();
148         mCodeCoverageListener.testRunEnded(ELAPSED_TIME, TfMetricProtoUtil.upgradeConvert(metric));
149 
150         // Verify testLog(..) was called with an empty zip.
151         List<ByteString> logs = mFakeListener.getLogs();
152         assertThat(logs).hasSize(1);
153         File outputZip = folder.newFile("empty_coverage.zip");
154         try (OutputStream out = new FileOutputStream(outputZip)) {
155             logs.get(0).writeTo(out);
156         }
157 
158         ZipFile loggedZip = new ZipFile(outputZip);
159         assertThat(loggedZip.size()).isEqualTo(0);
160     }
161 
162     @Test
testFailure_unableToPullFile()163     public void testFailure_unableToPullFile() throws DeviceNotAvailableException {
164         // Setup mocks.
165         doReturn(true).when(mMockDevice).enableAdbRoot();
166         doReturn("/data/misc/trace/proc/self/cwd/out/some/path/to/coverage.gcda\n")
167                 .when(mMockDevice)
168                 .executeShellCommand(anyString());
169         doReturn(false).when(mMockDevice).pullFile(anyString(), any());
170 
171         // Simulate a test run.
172         mCodeCoverageListener.testRunStarted(RUN_NAME, TEST_COUNT);
173 
174         Map<String, String> metric = new HashMap<>();
175         try {
176             mCodeCoverageListener.testRunEnded(
177                     ELAPSED_TIME, TfMetricProtoUtil.upgradeConvert(metric));
178             fail("an exception should have been thrown.");
179         } catch (VerifyException e) {
180             // Expected
181         }
182 
183         // Verify testLog(..) was not called.
184         assertThat(mFakeListener.getLogs()).isEmpty();
185     }
186 
187     /** An {@link ITestInvocationListener} which reads test log data streams for verification. */
188     private static class LogFileReader implements ITestInvocationListener {
189         private List<ByteString> mLogs = new ArrayList<>();
190 
191         /** Reads the contents of the {@code dataStream} and saves it in the logs. */
192         @Override
testLog(String dataName, LogDataType dataType, InputStreamSource dataStream)193         public void testLog(String dataName, LogDataType dataType, InputStreamSource dataStream) {
194             try (InputStream input = dataStream.createInputStream()) {
195                 mLogs.add(ByteString.readFrom(input));
196             } catch (IOException e) {
197                 throw new RuntimeException(e);
198             }
199         }
200 
getLogs()201         List<ByteString> getLogs() {
202             return new ArrayList<>(mLogs);
203         }
204     }
205 }
206