Skip to content

Commit

Permalink
add integration tests that use the static table
Browse files Browse the repository at this point in the history
  • Loading branch information
marten-seemann committed Aug 8, 2020
1 parent f857198 commit c48a52d
Show file tree
Hide file tree
Showing 3 changed files with 159 additions and 3 deletions.
138 changes: 135 additions & 3 deletions integrationtests/self/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package self

import (
"bytes"
"fmt"
"math/rand"

"github.com/marten-seemann/qpack"

Expand All @@ -28,8 +30,21 @@ var _ = Describe("Self Tests", func() {
})
})

randomString := func(l int) string {
const charset = "abcdefghijklmnopqrstuvwxyz" +
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
s := make([]byte, l)
for i := range s {
s[i] = charset[rand.Intn(len(charset))]
}
return string(s)
}

It("encodes and decodes a single header field", func() {
hf := qpack.HeaderField{Name: "foo", Value: "bar"}
hf := qpack.HeaderField{
Name: randomString(15),
Value: randomString(15),
}
Expect(encoder.WriteField(hf)).To(Succeed())
_, err := decoder.Write(output.Bytes())
Expect(err).ToNot(HaveOccurred())
Expand All @@ -40,7 +55,7 @@ var _ = Describe("Self Tests", func() {
hfs := []qpack.HeaderField{
{Name: "foo", Value: "bar"},
{Name: "lorem", Value: "ipsum"},
{Name: "name", Value: "value"},
{Name: randomString(15), Value: randomString(20)},
}
for _, hf := range hfs {
Expect(encoder.WriteField(hf)).To(Succeed())
Expand All @@ -54,7 +69,7 @@ var _ = Describe("Self Tests", func() {
hfs1 := []qpack.HeaderField{{Name: "foo", Value: "bar"}}
hfs2 := []qpack.HeaderField{
{Name: "lorem", Value: "ipsum"},
{Name: "name", Value: "value"},
{Name: randomString(15), Value: randomString(20)},
}
for _, hf := range hfs1 {
Expect(encoder.WriteField(hf)).To(Succeed())
Expand All @@ -74,4 +89,121 @@ var _ = Describe("Self Tests", func() {
Expect(err).ToNot(HaveOccurred())
Expect(headerFields).To(Equal(hfs2))
})

// replace one character by a random character at a random position
replaceRandomCharacter := func(s string) string {
pos := rand.Intn(len(s))
new := s[:pos]
for {
if c := randomString(1); c != string(s[pos]) {
new += c
break
}
}
new += s[pos+1:]
return new
}

check := func(encoded []byte, hf qpack.HeaderField) {
hfs, err := decoder.DecodeFull(encoded)
ExpectWithOffset(1, err).ToNot(HaveOccurred())
Expect(hfs).To(HaveLen(1))
Expect(hfs[0]).To(Equal(hf))
}

// use an entry with a value, for example "set-cookie"
It("uses the static table for field names, for fields without values", func() {
var hf qpack.HeaderField
for {
if entry := staticTable[rand.Intn(len(staticTable))]; len(entry.Value) == 0 {
hf = qpack.HeaderField{Name: entry.Name}
break
}
}
Expect(encoder.WriteField(hf)).To(Succeed())
encodedLen := output.Len()
check(output.Bytes(), hf)
output.Reset()
oldName := hf.Name
hf.Name = replaceRandomCharacter(hf.Name)
Expect(encoder.WriteField(hf)).To(Succeed())
fmt.Fprintf(GinkgoWriter, "Encoding field name:\n\t%s: %d bytes\n\t%s: %d bytes\n", oldName, encodedLen, hf.Name, output.Len())
Expect(output.Len()).To(BeNumerically(">", encodedLen))
})

// use an entry with a value, for example "set-cookie",
// but now use a custom value
It("uses the static table for field names, for fields without values", func() {
var hf qpack.HeaderField
for {
if entry := staticTable[rand.Intn(len(staticTable))]; len(entry.Value) == 0 {
hf = qpack.HeaderField{
Name: entry.Name,
Value: randomString(5),
}
break
}
}
Expect(encoder.WriteField(hf)).To(Succeed())
encodedLen := output.Len()
check(output.Bytes(), hf)
output.Reset()
oldName := hf.Name
hf.Name = replaceRandomCharacter(hf.Name)
Expect(encoder.WriteField(hf)).To(Succeed())
fmt.Fprintf(GinkgoWriter, "Encoding field name:\n\t%s: %d bytes\n\t%s: %d bytes\n", oldName, encodedLen, hf.Name, output.Len())
Expect(output.Len()).To(BeNumerically(">", encodedLen))
})

// use an entry with a value, for example
// cache-control -> Value: "max-age=0"
// but encode a different value
// cache-control -> xyz
It("uses the static table for field names, for fields with values", func() {
var hf qpack.HeaderField
for {
if entry := staticTable[rand.Intn(len(staticTable))]; len(entry.Value) > 0 {
hf = qpack.HeaderField{
Name: entry.Name,
Value: randomString(20),
}
break
}
}
Expect(encoder.WriteField(hf)).To(Succeed())
encodedLen := output.Len()
check(output.Bytes(), hf)
output.Reset()
oldName := hf.Name
hf.Name = replaceRandomCharacter(hf.Name)
Expect(encoder.WriteField(hf)).To(Succeed())
fmt.Fprintf(GinkgoWriter, "Encoding field name:\n\t%s: %d bytes\n\t%s: %d bytes\n", oldName, encodedLen, hf.Name, output.Len())
Expect(output.Len()).To(BeNumerically(">", encodedLen))
})

It("uses the static table for field values", func() {
var hf qpack.HeaderField
for {
if entry := staticTable[rand.Intn(len(staticTable))]; len(entry.Value) > 0 {
hf = qpack.HeaderField{
Name: entry.Name,
Value: entry.Value,
}
break
}
}
Expect(encoder.WriteField(hf)).To(Succeed())
encodedLen := output.Len()
check(output.Bytes(), hf)
output.Reset()
oldValue := hf.Value
hf.Value = replaceRandomCharacter(hf.Value)
Expect(encoder.WriteField(hf)).To(Succeed())
fmt.Fprintf(GinkgoWriter,
"Encoding field value:\n\t%s: %s -> %d bytes\n\t%s: %s -> %d bytes\n",
hf.Name, oldValue, encodedLen,
hf.Name, hf.Value, output.Len(),
)
Expect(output.Len()).To(BeNumerically(">", encodedLen))
})
})
17 changes: 17 additions & 0 deletions integrationtests/self/self_suite_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package self

import (
"math/rand"
"testing"
_ "unsafe"

"github.com/marten-seemann/qpack"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
Expand All @@ -11,3 +15,16 @@ func TestSelf(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Self Suite")
}

var _ = BeforeSuite(func() {
rand.Seed(GinkgoRandomSeed())
})

var staticTable []qpack.HeaderField

//go:linkname getStaticTable github.com/marten-seemann/qpack.getStaticTable
func getStaticTable() []qpack.HeaderField

func init() {
staticTable = getStaticTable()
}
7 changes: 7 additions & 0 deletions static_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,13 @@ var staticTableEntries = [...]HeaderField{
{Name: "x-frame-options", Value: "sameorigin"},
}

// Only needed for tests.
// use go:linkname to retrieve the static table.
//nolint:deadcode,unused
func getStaticTable() []HeaderField {
return staticTableEntries[:]
}

type indexAndValues struct {
idx uint8
values map[string]uint8
Expand Down

0 comments on commit c48a52d

Please sign in to comment.