summaryrefslogtreecommitdiffstats
path: root/components/cronet/android/test/javatests/src/org/chromium/net/QuicTest.java
blob: 655c2f398abf60351dc638eddab671fab89460c4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.net;

import android.test.suitebuilder.annotation.LargeTest;
import android.test.suitebuilder.annotation.SmallTest;

import org.chromium.base.Log;
import org.chromium.base.annotations.SuppressFBWarnings;
import org.chromium.base.test.util.Feature;
import org.chromium.net.CronetTestBase.OnlyRunNativeCronet;
import org.json.JSONObject;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;

/**
 * Tests making requests using QUIC.
 */
public class QuicTest extends CronetTestBase {
    private static final String TAG = "cr.QuicTest";
    private CronetTestFramework mTestFramework;
    private CronetEngine.Builder mBuilder;

    @Override
    protected void setUp() throws Exception {
        super.setUp();
        // Load library first, since we need the Quic test server's URL.
        System.loadLibrary("cronet_tests");
        QuicTestServer.startQuicTestServer(getContext());

        mBuilder = new CronetEngine.Builder(getContext());
        mBuilder.enableQUIC(true);
        mBuilder.addQuicHint(QuicTestServer.getServerHost(), QuicTestServer.getServerPort(),
                QuicTestServer.getServerPort());

        JSONObject quicParams = new JSONObject()
                                        .put("connection_options", "PACE,IW10,FOO,DEADBEEF")
                                        .put("host_whitelist", "test.example.com")
                                        .put("max_server_configs_stored_in_properties", 2)
                                        .put("delay_tcp_race", true)
                                        .put("max_number_of_lossy_connections", 10)
                                        .put("packet_loss_threshold", 0.5)
                                        .put("idle_connection_timeout_seconds", 300)
                                        .put("close_sessions_on_ip_change", true)
                                        .put("migrate_sessions_on_network_change", true);
        JSONObject experimentalOptions = new JSONObject().put("QUIC", quicParams);
        mBuilder.setExperimentalOptions(experimentalOptions.toString());

        mBuilder.setMockCertVerifierForTesting(QuicTestServer.createMockCertVerifier());
        mBuilder.setStoragePath(CronetTestFramework.getTestStorage(getContext()));
        mBuilder.enableHttpCache(CronetEngine.Builder.HTTP_CACHE_DISK_NO_HTTP, 1000 * 1024);
    }

    @Override
    protected void tearDown() throws Exception {
        QuicTestServer.shutdownQuicTestServer();
        super.tearDown();
    }

    @SmallTest
    @Feature({"Cronet"})
    @SuppressWarnings("deprecation")
    @OnlyRunNativeCronet
    public void testQuicLoadUrl_LegacyAPI() throws Exception {
        String[] commandLineArgs = {
                CronetTestFramework.LIBRARY_INIT_KEY, CronetTestFramework.LibraryInitType.LEGACY};
        mTestFramework = new CronetTestFramework(null, commandLineArgs, getContext(), mBuilder);
        registerHostResolver(mTestFramework, true);
        String quicURL = QuicTestServer.getServerURL() + "/simple.txt";

        HashMap<String, String> headers = new HashMap<String, String>();
        TestHttpUrlRequestListener listener = new TestHttpUrlRequestListener();

        // Although the native stack races QUIC and SPDY for the first request,
        // since there is no http server running on the corresponding TCP port,
        // QUIC will always succeed with a 200 (see
        // net::HttpStreamFactoryImpl::Request::OnStreamFailed).
        HttpUrlRequest request = mTestFramework.mRequestFactory.createRequest(
                quicURL, HttpUrlRequest.REQUEST_PRIORITY_MEDIUM, headers, listener);
        request.start();
        listener.blockForComplete();
        assertEquals(200, listener.mHttpStatusCode);
        assertEquals(
                "This is a simple text file served by QUIC.\n",
                listener.mResponseAsString);
        assertEquals("quic/1+spdy/3", listener.mNegotiatedProtocol);
    }

    @LargeTest
    @Feature({"Cronet"})
    @OnlyRunNativeCronet
    public void testQuicLoadUrl() throws Exception {
        mTestFramework = startCronetTestFrameworkWithUrlAndCronetEngineBuilder(null, mBuilder);
        registerHostResolver(mTestFramework);
        String quicURL = QuicTestServer.getServerURL() + "/simple.txt";
        TestUrlRequestCallback callback = new TestUrlRequestCallback();

        // Although the native stack races QUIC and SPDY for the first request,
        // since there is no http server running on the corresponding TCP port,
        // QUIC will always succeed with a 200 (see
        // net::HttpStreamFactoryImpl::Request::OnStreamFailed).
        UrlRequest.Builder requestBuilder = new UrlRequest.Builder(
                quicURL, callback, callback.getExecutor(), mTestFramework.mCronetEngine);
        requestBuilder.build().start();
        callback.blockForDone();

        assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
        String expectedContent = "This is a simple text file served by QUIC.\n";
        assertEquals(expectedContent, callback.mResponseAsString);
        assertEquals("quic/1+spdy/3", callback.mResponseInfo.getNegotiatedProtocol());
        // The total received bytes should be larger than the content length, to account for
        // headers.
        assertTrue(callback.mResponseInfo.getReceivedBytesCount() > expectedContent.length());
        // This test takes a long time, since the update will only be scheduled
        // after kUpdatePrefsDelayMs in http_server_properties_manager.cc.
        while (true) {
            Log.i(TAG, "Still waiting for pref file update.....");
            Thread.sleep(10000);
            boolean contains = false;
            try {
                if (fileContainsString("local_prefs.json", "quic")) break;
            } catch (FileNotFoundException e) {
                // Ignored this exception since the file will only be created when updates are
                // flushed to the disk.
            }
        }
        assertTrue(fileContainsString("local_prefs.json",
                QuicTestServer.getServerHost() + ":" + QuicTestServer.getServerPort()));
        mTestFramework.mCronetEngine.shutdown();

        // Make another request using a new context but with no QUIC hints.
        CronetEngine.Builder builder = new CronetEngine.Builder(getContext());
        builder.setStoragePath(CronetTestFramework.getTestStorage(getContext()));
        builder.enableHttpCache(CronetEngine.Builder.HTTP_CACHE_DISK, 1000 * 1024);
        builder.enableQUIC(true);
        JSONObject quicParams = new JSONObject().put("host_whitelist", "test.example.com");
        JSONObject experimentalOptions = new JSONObject().put("QUIC", quicParams);
        builder.setExperimentalOptions(experimentalOptions.toString());
        builder.setMockCertVerifierForTesting(QuicTestServer.createMockCertVerifier());
        mTestFramework = startCronetTestFrameworkWithUrlAndCronetEngineBuilder(null, builder);
        registerHostResolver(mTestFramework);
        TestUrlRequestCallback callback2 = new TestUrlRequestCallback();
        requestBuilder = new UrlRequest.Builder(
                quicURL, callback2, callback2.getExecutor(), mTestFramework.mCronetEngine);
        requestBuilder.build().start();
        callback2.blockForDone();
        assertEquals(200, callback2.mResponseInfo.getHttpStatusCode());
        assertEquals(expectedContent, callback2.mResponseAsString);
        assertEquals("quic/1+spdy/3", callback2.mResponseInfo.getNegotiatedProtocol());
        // The total received bytes should be larger than the content length, to account for
        // headers.
        assertTrue(callback2.mResponseInfo.getReceivedBytesCount() > expectedContent.length());
    }

    // Returns whether a file contains a particular string.
    @SuppressFBWarnings("OBL_UNSATISFIED_OBLIGATION_EXCEPTION_EDGE")
    private boolean fileContainsString(String filename, String content) throws IOException {
        File file = new File(CronetTestFramework.getTestStorage(getContext()) + "/" + filename);
        FileInputStream fileInputStream = new FileInputStream(file);
        byte[] data = new byte[(int) file.length()];
        fileInputStream.read(data);
        fileInputStream.close();
        return new String(data, "UTF-8").contains(content);
    }
}