aboutsummaryrefslogtreecommitdiff
path: root/types/http_test.go
diff options
context:
space:
mode:
authorRasmus Dahlberg <rasmus.dahlberg@kau.se>2021-05-17 22:04:33 +0200
committerRasmus Dahlberg <rasmus.dahlberg@kau.se>2021-05-17 22:04:33 +0200
commit2b2fc76121699e20c60dabb40e4507128731c0d5 (patch)
tree677c5ab6a4a64045c062c3f38c5d66cd0facb16f /types/http_test.go
parent5a780e8cd56509218123671be5826cbd2f0e8d2c (diff)
started to refactor types and parsers
Work in progress.
Diffstat (limited to 'types/http_test.go')
-rw-r--r--types/http_test.go322
1 files changed, 322 insertions, 0 deletions
diff --git a/types/http_test.go b/types/http_test.go
new file mode 100644
index 0000000..8165edf
--- /dev/null
+++ b/types/http_test.go
@@ -0,0 +1,322 @@
+package types
+
+import (
+ "bytes"
+ "encoding/hex"
+ "net/http"
+ "reflect"
+ "strings"
+ "testing"
+)
+
+var (
+ testZeroBuffer32 = [32]byte{}
+ testZeroBuffer64 = [64]byte{}
+)
+
+func TestSignedTreeHeadToHTTP(t *testing.T) {
+ description := "valid: cosigned tree head with two signatures"
+ sth := &SignedTreeHead{
+ TreeHead: TreeHead{
+ Timestamp: 0,
+ TreeSize: 0,
+ RootHash: testBuffer32,
+ },
+ SigIdent: []SigIdent{
+ SigIdent{
+ Signature: testZeroBuffer64,
+ KeyHash: testZeroBuffer32,
+ },
+ SigIdent{
+ Signature: testBuffer64,
+ KeyHash: testBuffer32,
+ },
+ },
+ }
+ want := map[string][]string{
+ HeaderTimestamp: []string{"0"},
+ HeaderTreeSize: []string{"0"},
+ HeaderRootHash: []string{hex.EncodeToString(testBuffer32[:])},
+ HeaderSignature: []string{
+ hex.EncodeToString(testZeroBuffer64[:]),
+ hex.EncodeToString(testBuffer64[:]),
+ },
+ HeaderKeyHash: []string{
+ hex.EncodeToString(testZeroBuffer32[:]),
+ hex.EncodeToString(testBuffer32[:]),
+ },
+ }
+ buf, err := sth.ToHTTP()
+ if err != nil {
+ t.Fatalf("sth.ToHTTP: %v", err)
+ }
+ hdr, err := headerFromBuf(buf)
+ if err != nil {
+ t.Fatalf("headerFromBuf: %v", err)
+ }
+ compareHeaderWithMap(t, description, hdr, want)
+}
+
+func TestSignedTreeHeadFromHTTP(t *testing.T) {
+ for _, table := range []struct {
+ description string
+ buf []byte
+ wantErr bool
+ wantSth *SignedTreeHead
+ }{
+ {
+ description: "invalid: not ST log HTTP header",
+ buf: newHeaderBuf(t, map[string][]string{
+ "user-agent": []string{"secret"},
+ }),
+ wantErr: true,
+ },
+ {
+ description: "invalid: timestamp",
+ buf: newHeaderBuf(t, map[string][]string{
+ HeaderTreeSize: []string{"0"},
+ HeaderRootHash: []string{hex.EncodeToString(testBuffer32[:])},
+ HeaderSignature: []string{hex.EncodeToString(testBuffer64[:])},
+ HeaderKeyHash: []string{hex.EncodeToString(testBuffer32[:])},
+ }),
+ wantErr: true,
+ },
+ {
+ description: "invalid: tree size",
+ buf: newHeaderBuf(t, map[string][]string{
+ HeaderTimestamp: []string{"0"},
+ HeaderRootHash: []string{hex.EncodeToString(testBuffer32[:])},
+ HeaderSignature: []string{hex.EncodeToString(testBuffer64[:])},
+ HeaderKeyHash: []string{hex.EncodeToString(testBuffer32[:])},
+ }),
+ wantErr: true,
+ },
+ {
+ description: "invalid: root hash",
+ buf: newHeaderBuf(t, map[string][]string{
+ HeaderTimestamp: []string{"0"},
+ HeaderTreeSize: []string{"0"},
+ HeaderSignature: []string{hex.EncodeToString(testBuffer64[:])},
+ HeaderKeyHash: []string{hex.EncodeToString(testBuffer32[:])},
+ }),
+ wantErr: true,
+ },
+ {
+ description: "invalid: signature",
+ buf: newHeaderBuf(t, map[string][]string{
+ HeaderTimestamp: []string{"0"},
+ HeaderTreeSize: []string{"0"},
+ HeaderRootHash: []string{hex.EncodeToString(testBuffer32[:])},
+ HeaderSignature: []string{hex.EncodeToString(testBuffer32[:])},
+ HeaderKeyHash: []string{hex.EncodeToString(testBuffer32[:])},
+ }),
+ wantErr: true,
+ },
+ {
+ description: "invalid: key hash",
+ buf: newHeaderBuf(t, map[string][]string{
+ HeaderTimestamp: []string{"0"},
+ HeaderTreeSize: []string{"0"},
+ HeaderRootHash: []string{hex.EncodeToString(testBuffer32[:])},
+ HeaderSignature: []string{hex.EncodeToString(testBuffer64[:])},
+ HeaderKeyHash: []string{hex.EncodeToString(testBuffer64[:])},
+ }),
+ wantErr: true,
+ },
+ {
+ description: "invalid: sigident count",
+ buf: newHeaderBuf(t, map[string][]string{
+ HeaderTimestamp: []string{"0"},
+ HeaderTreeSize: []string{"0"},
+ HeaderRootHash: []string{hex.EncodeToString(testBuffer32[:])},
+ HeaderSignature: []string{hex.EncodeToString(testBuffer64[:])},
+ HeaderKeyHash: []string{
+ hex.EncodeToString(testZeroBuffer32[:]),
+ hex.EncodeToString(testBuffer32[:]),
+ },
+ }),
+ wantErr: true,
+ },
+ {
+ description: "invalid: no signer",
+ buf: newHeaderBuf(t, map[string][]string{
+ HeaderTimestamp: []string{"0"},
+ HeaderTreeSize: []string{"0"},
+ HeaderRootHash: []string{hex.EncodeToString(testBuffer32[:])},
+ }),
+ wantErr: true,
+ },
+ {
+ description: "valid: cosigned tree head with two signatures",
+ buf: newHeaderBuf(t, map[string][]string{
+ HeaderTimestamp: []string{"0"},
+ HeaderTreeSize: []string{"0"},
+ HeaderRootHash: []string{hex.EncodeToString(testBuffer32[:])},
+ HeaderSignature: []string{
+ hex.EncodeToString(testZeroBuffer64[:]),
+ hex.EncodeToString(testBuffer64[:]),
+ },
+ HeaderKeyHash: []string{
+ hex.EncodeToString(testZeroBuffer32[:]),
+ hex.EncodeToString(testBuffer32[:]),
+ },
+ }),
+ wantSth: &SignedTreeHead{
+ TreeHead: TreeHead{
+ Timestamp: 0,
+ TreeSize: 0,
+ RootHash: testBuffer32,
+ },
+ SigIdent: []SigIdent{
+ SigIdent{
+ Signature: testZeroBuffer64,
+ KeyHash: testZeroBuffer32,
+ },
+ SigIdent{
+ Signature: testBuffer64,
+ KeyHash: testBuffer32,
+ },
+ },
+ },
+ },
+ } {
+ sth, err := SignedTreeHeadFromHTTP(table.buf)
+ if got, want := err != nil, table.wantErr; got != want {
+ t.Errorf("got error %v but wanted %v in test %q: %v", got, want, table.description, err)
+ }
+ if err != nil {
+ continue // nothing more to check on error
+ }
+ if got, want := sth, table.wantSth; !reflect.DeepEqual(got, want) {
+ t.Errorf("got signed tree head\n\t%v\nbut wanted\n\t%v\nin test %q", got, want, table.description)
+ }
+ }
+}
+
+func TestHeaderFromBuf(t *testing.T) {
+ for _, table := range []struct {
+ description string
+ buf []byte
+ wantErr bool
+ wantMap map[string][]string
+ }{
+ {
+ description: "invalid: split",
+ buf: []byte(HeaderPrefix + "k1: v1:v2\r\n"),
+ wantErr: true,
+ },
+ {
+ description: "invalid: prefix",
+ buf: []byte("user-agent: secret\r\n"),
+ wantErr: true,
+ },
+ {
+ description: "valid: one key with funky case",
+ buf: []byte(funkyCase(t, HeaderPrefix) + "k1: v1\r\n"),
+ wantMap: map[string][]string{
+ HeaderPrefix + "k1": []string{"v1"},
+ },
+ },
+ {
+ description: "valid: two keys where one has multiple values",
+ buf: []byte(
+ HeaderPrefix + "k1: v1 \r\n" +
+ HeaderPrefix + "k2: v2\r\n" +
+ HeaderPrefix + "k2: v3\r\n",
+ ),
+ wantMap: map[string][]string{
+ HeaderPrefix + "k1": []string{"v1"},
+ HeaderPrefix + "k2": []string{"v2", "v3"},
+ },
+ },
+ } {
+ hdr, err := headerFromBuf(table.buf)
+ if got, want := err != nil, table.wantErr; got != want {
+ t.Errorf("got error %v but wanted %v in test %q: %v", got, want, table.description, err)
+ }
+ if err != nil {
+ continue // nothing more to check on error
+ }
+ compareHeaderWithMap(t, table.description, hdr, table.wantMap)
+ }
+}
+
+func TestDecodeHex(t *testing.T) {
+ for _, table := range []struct {
+ description string
+ hex string
+ wantErr bool
+ wantBuf [4]byte
+ }{
+ {
+ description: "invalid: too short input",
+ hex: "000102",
+ wantErr: true,
+ },
+ {
+ description: "invalid: too large input",
+ hex: "0001020304",
+ wantErr: true,
+ },
+ {
+ description: "invalid: not hex (1/2)",
+ hex: "000102030",
+ wantErr: true,
+ },
+ {
+ description: "invalid: not hex (2/2)",
+ hex: "0001020q",
+ wantErr: true,
+ },
+ {
+ description: "valid",
+ hex: "00010203",
+ wantBuf: [4]byte{0, 1, 2, 3},
+ },
+ } {
+ var buf [4]byte
+ err := decodeHex(table.hex, buf[:])
+ if got, want := err != nil, table.wantErr; got != want {
+ t.Errorf("got error %v but wanted %v in test %q: %v", got, want, table.description, err)
+ }
+ if err != nil {
+ continue // nothing more to check on error
+ }
+ if got, want := buf[:], table.wantBuf[:]; !bytes.Equal(got, want) {
+ t.Errorf("got buf %v but wanted %v in test %q", got, want, table.description)
+ }
+ }
+}
+
+func newHeaderBuf(t *testing.T, kv map[string][]string) []byte {
+ t.Helper()
+ hdr := http.Header{}
+ for key, values := range kv {
+ for _, value := range values {
+ hdr.Add(key, value)
+ }
+ }
+ buf := bytes.NewBuffer(nil)
+ if err := hdr.Write(buf); err != nil {
+ t.Fatalf("hdr.Write(): %v", err)
+ }
+ return buf.Bytes()
+}
+
+func compareHeaderWithMap(t *testing.T, description string, hdr http.Header, wantMap map[string][]string) {
+ t.Helper()
+ if got, want := len(hdr), len(wantMap); got != want {
+ t.Errorf("got %d keys but wanted %d in test %q", got, want, description)
+ }
+ for key, value := range wantMap {
+ if got, want := hdr.Values(key), value; !reflect.DeepEqual(got, want) {
+ t.Errorf("got value %v but wanted %v for key %v in test %q", got, want, key, description)
+ }
+ }
+}
+
+func funkyCase(t *testing.T, str string) string {
+ t.Helper()
+ splitIndex := len(str) / 2
+ return strings.ToLower(str[:splitIndex]) + strings.ToUpper(str[splitIndex:])
+}