Skip to content

Commit ea13e5e

Browse files
committed
Add hpack-test-case test module.
Issue square#931
1 parent 5468a73 commit ea13e5e

12 files changed

+537
-0
lines changed

.gitmodules

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "okhttp-hpacktests/src/test/resources/hpack-test-case"]
2+
path = okhttp-hpacktests/src/test/resources/hpack-test-case
3+
url = git://github.com/http2jp/hpack-test-case.git

okhttp-hpacktests/README.md

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
OkHttp HPACK tests
2+
==================
3+
4+
These tests use the [hpack-test-case][1] project to validate OkHttp's HPACK
5+
implementation. The HPACK test cases are in a separate git submodule, so to
6+
initialize them, you must run:
7+
8+
git submodule init
9+
git submodule update
10+
11+
When new interop tests are available, you should update
12+
HpackDecodeInteropGoodTest#GOOD_INTEROP_TESTS with the directory name.
13+
14+
TODO
15+
----
16+
17+
* Add maven goal to avoid manual call to git submodule init.
18+
* Make hpack-test-case update itself from git, and run new tests.
19+
* Add maven goal to generate stories and a pull request to hpack-test-case
20+
to have others validate our output.
21+
22+
[1]: https://github.com/http2jp/hpack-test-case

okhttp-hpacktests/pom.xml

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
3+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
6+
<parent>
7+
<groupId>com.squareup.okhttp</groupId>
8+
<artifactId>parent</artifactId>
9+
<version>2.0.1-SNAPSHOT</version>
10+
</parent>
11+
12+
<artifactId>okhttp-hpacktests</artifactId>
13+
<name>OkHttp HPACK Tests</name>
14+
15+
<dependencies>
16+
<dependency>
17+
<groupId>com.squareup.okio</groupId>
18+
<artifactId>okio</artifactId>
19+
</dependency>
20+
<dependency>
21+
<groupId>com.squareup.okhttp</groupId>
22+
<artifactId>okhttp</artifactId>
23+
<version>${project.version}</version>
24+
</dependency>
25+
<dependency>
26+
<groupId>junit</groupId>
27+
<artifactId>junit</artifactId>
28+
<scope>test</scope>
29+
</dependency>
30+
<dependency>
31+
<groupId>com.squareup.okhttp</groupId>
32+
<artifactId>mockwebserver</artifactId>
33+
<version>${project.version}</version>
34+
<scope>test</scope>
35+
</dependency>
36+
<!-- Gson: Java to Json conversion -->
37+
<dependency>
38+
<groupId>com.google.code.gson</groupId>
39+
<artifactId>gson</artifactId>
40+
<version>2.2.4</version>
41+
<scope>compile</scope>
42+
</dependency>
43+
</dependencies>
44+
45+
<build>
46+
<plugins>
47+
<!-- Do not deploy this as an artifact to Maven central. -->
48+
<plugin>
49+
<groupId>org.apache.maven.plugins</groupId>
50+
<artifactId>maven-deploy-plugin</artifactId>
51+
<configuration>
52+
<skip>true</skip>
53+
</configuration>
54+
</plugin>
55+
</plugins>
56+
</build>
57+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright (C) 2014 Square, Inc.
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.squareup.okhttp.internal.spdy;
17+
18+
import com.squareup.okhttp.internal.spdy.hpackjson.Story;
19+
import org.junit.Ignore;
20+
import org.junit.Test;
21+
import org.junit.runner.RunWith;
22+
import org.junit.runners.Parameterized;
23+
24+
import java.util.Collection;
25+
26+
/**
27+
* Known bad tests for HPACK interop.
28+
*/
29+
// TODO: fix these tests (see if the input/test is legit, fix the implementation.)
30+
@Ignore
31+
@RunWith(Parameterized.class)
32+
public class HpackDecodeInteropBadTest extends HpackDecodeTestBase {
33+
34+
private static final String[] BAD_INTEROP_TESTS = { "go-hpack", "haskell-http2-diff-huffman",
35+
"haskell-http2-linear-huffman", "haskell-http2-naive-huffman",
36+
"haskell-http2-static-huffman", "node-http2-protocol", "twitter-hpack" };
37+
38+
public HpackDecodeInteropBadTest(Story story) {
39+
super(story);
40+
}
41+
42+
@Parameterized.Parameters(name="{0}")
43+
public static Collection<Story[]> createStories() throws Exception {
44+
return createStories(BAD_INTEROP_TESTS);
45+
}
46+
47+
@Test
48+
public void testGoodDecoderInterop() throws Exception {
49+
testDecoder();
50+
}
51+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright (C) 2014 Square, Inc.
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.squareup.okhttp.internal.spdy;
17+
18+
import com.squareup.okhttp.internal.spdy.hpackjson.Story;
19+
import org.junit.Test;
20+
import org.junit.runner.RunWith;
21+
import org.junit.runners.Parameterized;
22+
23+
import java.util.Collection;
24+
25+
/**
26+
* Known good tests for HPACK interop.
27+
*/
28+
@RunWith(Parameterized.class)
29+
public class HpackDecodeInteropGoodTest extends HpackDecodeTestBase {
30+
31+
32+
private static final String[] GOOD_INTEROP_TESTS = { "haskell-http2-diff",
33+
"haskell-http2-linear", "haskell-http2-naive", "haskell-http2-static",
34+
"hyper-hpack", "nghttp2", "nghttp2-16384-4096",
35+
"nghttp2-change-table-size", "node-http2-hpack" };
36+
37+
public HpackDecodeInteropGoodTest(Story story) {
38+
super(story);
39+
}
40+
41+
@Parameterized.Parameters(name="{0}")
42+
public static Collection<Story[]> createStories() throws Exception {
43+
return createStories(GOOD_INTEROP_TESTS);
44+
}
45+
46+
@Test
47+
public void testGoodDecoderInterop() throws Exception {
48+
testDecoder();
49+
}
50+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
* Copyright (C) 2014 Square, Inc.
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.squareup.okhttp.internal.spdy;
17+
18+
import static org.junit.Assert.assertEquals;
19+
import static org.junit.Assert.fail;
20+
21+
import com.squareup.okhttp.internal.spdy.hpackjson.Case;
22+
import com.squareup.okhttp.internal.spdy.hpackjson.HpackJsonUtil;
23+
import com.squareup.okhttp.internal.spdy.hpackjson.Story;
24+
import okio.Buffer;
25+
26+
import java.util.ArrayList;
27+
import java.util.Collection;
28+
import java.util.LinkedHashSet;
29+
import java.util.List;
30+
31+
/**
32+
* Tests Hpack implementation using https://github.com/http2jp/hpack-test-case/
33+
*/
34+
public class HpackDecodeTestBase {
35+
36+
/**
37+
* Reads all stories in the folders provided, asserts if no story found.
38+
*/
39+
protected static Collection<Story[]> createStories(String[] interopTests)
40+
throws Exception {
41+
List<Story[]> result = new ArrayList<>();
42+
for (String interopTestName : interopTests) {
43+
List<Story> stories = HpackJsonUtil.readStories(interopTestName);
44+
if (stories.isEmpty()) {
45+
fail("No stories for: " + interopTestName);
46+
}
47+
for (Story story : stories) {
48+
result.add(new Story[] { story });
49+
}
50+
}
51+
return result;
52+
}
53+
54+
private final Buffer bytesIn = new Buffer();
55+
private final HpackDraft08.Reader hpackReader = new HpackDraft08.Reader(4096, bytesIn);
56+
57+
private final Story story;
58+
59+
public HpackDecodeTestBase(Story story) {
60+
this.story = story;
61+
}
62+
63+
/**
64+
* Expects wire to be set for all cases, and compares the decoder's output to
65+
* expected headers.
66+
*/
67+
protected void testDecoder() throws Exception {
68+
testDecoder(story);
69+
}
70+
71+
protected void testDecoder(Story story) throws Exception {
72+
for (Case caze : story.getCases()) {
73+
bytesIn.write(caze.getWire());
74+
hpackReader.readHeaders();
75+
hpackReader.emitReferenceSet();
76+
assertSetEquals(String.format("seqno=%d", caze.getSeqno()), caze.getHeaders(),
77+
hpackReader.getAndReset());
78+
}
79+
}
80+
/**
81+
* Checks if {@code expected} and {@code observed} are equal when viewed as a
82+
* set and headers are deduped.
83+
*
84+
* TODO: See if duped headers should be preserved on decode and verify.
85+
*/
86+
private static void assertSetEquals(
87+
String message, List<Header> expected, List<Header> observed) {
88+
assertEquals(message, new LinkedHashSet<>(expected), new LinkedHashSet<>(observed));
89+
}
90+
91+
protected Story getStory() {
92+
return story;
93+
}
94+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright (C) 2014 Square, Inc.
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.squareup.okhttp.internal.spdy;
17+
18+
import com.squareup.okhttp.internal.spdy.hpackjson.Case;
19+
import com.squareup.okhttp.internal.spdy.hpackjson.Story;
20+
import okio.Buffer;
21+
import org.junit.Test;
22+
import org.junit.runner.RunWith;
23+
import org.junit.runners.Parameterized;
24+
25+
import java.util.Collection;
26+
27+
/**
28+
* Tests for round-tripping headers through hpack..
29+
*/
30+
// TODO: update hpack-test-case with the output of our encoder.
31+
// This test will hide complementary bugs in the encoder and decoder,
32+
// We should test that the encoder is producing responses that are
33+
// d]
34+
@RunWith(Parameterized.class)
35+
public class HpackRoundTripTest extends HpackDecodeTestBase {
36+
37+
private static final String[] RAW_DATA = { "raw-data" };
38+
39+
@Parameterized.Parameters(name="{0}")
40+
public static Collection<Story[]> getStories() throws Exception {
41+
return createStories(RAW_DATA);
42+
}
43+
44+
private Buffer bytesOut = new Buffer();
45+
private HpackDraft08.Writer hpackWriter = new HpackDraft08.Writer(bytesOut);
46+
47+
public HpackRoundTripTest(Story story) {
48+
super(story);
49+
}
50+
51+
@Test
52+
public void testRoundTrip() throws Exception {
53+
Story story = getStory().clone();
54+
// Mutate cases in base class.
55+
for (Case caze : story.getCases()) {
56+
hpackWriter.writeHeaders(caze.getHeaders());
57+
caze.setWire(bytesOut.readByteString());
58+
}
59+
60+
testDecoder(story);
61+
}
62+
63+
}

0 commit comments

Comments
 (0)