1 // Copyright 2018 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.net; 6 7 import static com.google.common.truth.Truth.assertThat; 8 9 import static org.chromium.net.truth.UrlResponseInfoSubject.assertThat; 10 11 import android.os.Build; 12 13 import androidx.test.ext.junit.runners.AndroidJUnit4; 14 import androidx.test.filters.SmallTest; 15 16 import org.junit.After; 17 import org.junit.Before; 18 import org.junit.Rule; 19 import org.junit.Test; 20 import org.junit.runner.RunWith; 21 22 import org.chromium.base.test.util.DoNotBatch; 23 import org.chromium.net.CronetTestRule.CronetImplementation; 24 import org.chromium.net.CronetTestRule.IgnoreFor; 25 26 /** Tests requests that generate Network Error Logging reports. */ 27 @DoNotBatch(reason = "crbug/1459563") 28 @RunWith(AndroidJUnit4.class) 29 @IgnoreFor( 30 implementations = {CronetImplementation.FALLBACK, CronetImplementation.AOSP_PLATFORM}, 31 reason = "Fallback and AOSP implementations do not support network error logging") 32 public class NetworkErrorLoggingTest { 33 @Rule public final CronetTestRule mTestRule = CronetTestRule.withManualEngineStartup(); 34 35 @Before setUp()36 public void setUp() throws Exception { 37 // TODO(crbug/1490552): Fallback to MockCertVerifier when custom CAs are not supported. 38 if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) { 39 mTestRule 40 .getTestFramework() 41 .applyEngineBuilderPatch( 42 (builder) -> { 43 CronetTestUtil.setMockCertVerifierForTesting( 44 builder, QuicTestServer.createMockCertVerifier()); 45 }); 46 } 47 assertThat(Http2TestServer.startHttp2TestServer(mTestRule.getTestFramework().getContext())) 48 .isTrue(); 49 } 50 51 @After tearDown()52 public void tearDown() throws Exception { 53 assertThat(Http2TestServer.shutdownHttp2TestServer()).isTrue(); 54 } 55 56 @Test 57 @SmallTest testManualReportUpload()58 public void testManualReportUpload() throws Exception { 59 String url = Http2TestServer.getReportingCollectorUrl(); 60 TestUrlRequestCallback callback = new TestUrlRequestCallback(); 61 UrlRequest.Builder requestBuilder = 62 mTestRule 63 .getTestFramework() 64 .startEngine() 65 .newUrlRequestBuilder(url, callback, callback.getExecutor()); 66 TestUploadDataProvider dataProvider = 67 new TestUploadDataProvider( 68 TestUploadDataProvider.SuccessCallbackMode.SYNC, callback.getExecutor()); 69 dataProvider.addRead("[{\"type\": \"test_report\"}]".getBytes()); 70 requestBuilder.setUploadDataProvider(dataProvider, callback.getExecutor()); 71 requestBuilder.addHeader("Content-Type", "application/reports+json"); 72 requestBuilder.build().start(); 73 callback.blockForDone(); 74 dataProvider.assertClosed(); 75 assertThat(callback.getResponseInfoWithChecks()).hasHttpStatusCodeThat().isEqualTo(200); 76 Http2TestServer.getReportingCollector().assertContainsReport("{\"type\": \"test_report\"}"); 77 } 78 79 @Test 80 @SmallTest testUploadNELReportsFromHeaders()81 public void testUploadNELReportsFromHeaders() throws Exception { 82 mTestRule 83 .getTestFramework() 84 .applyEngineBuilderPatch( 85 (builder) -> { 86 builder.setExperimentalOptions( 87 "{\"NetworkErrorLogging\": {\"enable\": true}}"); 88 }); 89 String url = Http2TestServer.getSuccessWithNELHeadersUrl(); 90 TestUrlRequestCallback callback = new TestUrlRequestCallback(); 91 UrlRequest.Builder requestBuilder = 92 mTestRule 93 .getTestFramework() 94 .startEngine() 95 .newUrlRequestBuilder(url, callback, callback.getExecutor()); 96 requestBuilder.build().start(); 97 callback.blockForDone(); 98 assertThat(callback.getResponseInfoWithChecks()).hasHttpStatusCodeThat().isEqualTo(200); 99 Http2TestServer.getReportingCollector().waitForReports(1); 100 Http2TestServer.getReportingCollector() 101 .assertContainsReport( 102 "" 103 + "{" 104 + " \"type\": \"network-error\"," 105 + " \"url\": \"" 106 + url 107 + "\"," 108 + " \"body\": {" 109 + " \"method\": \"GET\"," 110 + " \"phase\": \"application\"," 111 + " \"protocol\": \"h2\"," 112 + " \"referrer\": \"\"," 113 + " \"sampling_fraction\": 1.0," 114 + " \"status_code\": 200," 115 + " \"type\": \"ok\"" 116 + " }" 117 + "}"); 118 } 119 120 @Test 121 @SmallTest testUploadNELReportsFromPreloadedPolicy()122 public void testUploadNELReportsFromPreloadedPolicy() throws Exception { 123 mTestRule 124 .getTestFramework() 125 .applyEngineBuilderPatch( 126 (builder) -> { 127 String serverOrigin = Http2TestServer.getServerUrl(); 128 String collectorUrl = Http2TestServer.getReportingCollectorUrl(); 129 builder.setExperimentalOptions( 130 "" 131 + "{\"NetworkErrorLogging\": {" 132 + " \"enable\": true," 133 + " \"preloaded_report_to_headers\": [" 134 + " {" 135 + " \"origin\": \"" 136 + serverOrigin 137 + "\"," 138 + " \"value\": {" 139 + " \"group\": \"nel\"," 140 + " \"max_age\": 86400," 141 + " \"endpoints\": [" 142 + " {\"url\": \"" 143 + collectorUrl 144 + "\"}" 145 + " ]" 146 + " }" 147 + " }" 148 + " ]," 149 + " \"preloaded_nel_headers\": [" 150 + " {" 151 + " \"origin\": \"" 152 + serverOrigin 153 + "\"," 154 + " \"value\": {" 155 + " \"report_to\": \"nel\"," 156 + " \"max_age\": 86400," 157 + " \"success_fraction\": 1.0" 158 + " }" 159 + " }" 160 + " ]" 161 + "}}"); 162 }); 163 164 String url = Http2TestServer.getEchoMethodUrl(); 165 TestUrlRequestCallback callback = new TestUrlRequestCallback(); 166 UrlRequest.Builder requestBuilder = 167 mTestRule 168 .getTestFramework() 169 .startEngine() 170 .newUrlRequestBuilder(url, callback, callback.getExecutor()); 171 requestBuilder.build().start(); 172 callback.blockForDone(); 173 assertThat(callback.getResponseInfoWithChecks()).hasHttpStatusCodeThat().isEqualTo(200); 174 Http2TestServer.getReportingCollector().waitForReports(1); 175 // Note that because we don't know in advance what the server IP address is for preloaded 176 // origins, we'll always get a "downgraded" dns.address_changed NEL report if we don't 177 // receive a replacement NEL policy with the request. 178 Http2TestServer.getReportingCollector() 179 .assertContainsReport( 180 "" 181 + "{" 182 + " \"type\": \"network-error\"," 183 + " \"url\": \"" 184 + url 185 + "\"," 186 + " \"body\": {" 187 + " \"method\": \"GET\"," 188 + " \"phase\": \"dns\"," 189 + " \"protocol\": \"h2\"," 190 + " \"referrer\": \"\"," 191 + " \"sampling_fraction\": 1.0," 192 + " \"status_code\": 0," 193 + " \"type\": \"dns.address_changed\"" 194 + " }" 195 + "}"); 196 } 197 } 198