aboutsummaryrefslogtreecommitdiff
path: root/internal/node/secondary/endpoint_internal_test.go
blob: 9637e29d12985eb24374dcdef8c5b89149238082 (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
package secondary

import (
	"crypto"
	"crypto/ed25519"
	"fmt"
	"io"
	"net/http"
	"net/http/httptest"
	"testing"

	mocksDB "git.sigsum.org/log-go/internal/mocks/db"
	"git.sigsum.org/log-go/internal/node/handler"
	"git.sigsum.org/sigsum-go/pkg/merkle"
	"git.sigsum.org/sigsum-go/pkg/types"
	"github.com/golang/mock/gomock"
)

// TestSigner implements the signer interface.  It can be used to mock
// an Ed25519 signer that always return the same public key,
// signature, and error.
// NOTE: Code duplication with internal/state/single_test.go
type TestSigner struct {
	PublicKey [ed25519.PublicKeySize]byte
	Signature [ed25519.SignatureSize]byte
	Error     error
}

func (ts *TestSigner) Public() crypto.PublicKey {
	return ed25519.PublicKey(ts.PublicKey[:])
}

func (ts *TestSigner) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
	return ts.Signature[:], ts.Error
}

var (
	testTH = types.TreeHead{
		Timestamp: 0,
		TreeSize:  0,
		RootHash:  *merkle.HashFn([]byte("root hash")),
	}
	testSignerFailing    = TestSigner{types.PublicKey{}, types.Signature{}, fmt.Errorf("mocked error")}
	testSignerSucceeding = TestSigner{types.PublicKey{}, types.Signature{}, nil}
)

func TestGetTreeHeadToCosign(t *testing.T) {
	for _, tbl := range []struct {
		desc          string
		trillianTHErr error
		trillianTHRet *types.TreeHead
		signer        crypto.Signer
		httpStatus    int
	}{
		{
			desc:          "trillian GetTreeHead error",
			trillianTHErr: fmt.Errorf("mocked error"),
			httpStatus:    http.StatusInternalServerError,
		},
		{
			desc:          "signer error",
			trillianTHRet: &testTH,
			signer:        &testSignerFailing,
			httpStatus:    http.StatusInternalServerError,
		},
		{
			desc:          "success",
			trillianTHRet: &testTH,
			signer:        &testSignerSucceeding,
			httpStatus:    http.StatusOK,
		},
	} {
		func() {
			ctrl := gomock.NewController(t)
			defer ctrl.Finish()

			trillianClient := mocksDB.NewMockClient(ctrl)
			trillianClient.EXPECT().GetTreeHead(gomock.Any()).Return(tbl.trillianTHRet, tbl.trillianTHErr)

			node := Secondary{
				Config:         testConfig,
				TrillianClient: trillianClient,
				Signer:         tbl.signer,
			}

			// Create HTTP request
			url := types.EndpointAddLeaf.Path("http://example.com", node.Prefix())
			req, err := http.NewRequest("GET", url, nil)
			if err != nil {
				t.Fatalf("must create http request: %v", err)
			}

			// Run HTTP request
			w := httptest.NewRecorder()
			mustHandleInternal(t, node, types.EndpointGetTreeHeadToCosign).ServeHTTP(w, req)
			if got, want := w.Code, tbl.httpStatus; got != want {
				t.Errorf("got HTTP status code %v but wanted %v in test %q", got, want, tbl.desc)
			}
		}()
	}
}

func mustHandleInternal(t *testing.T, s Secondary, e types.Endpoint) handler.Handler {
	for _, h := range s.InternalHTTPHandlers() {
		if h.Endpoint == e {
			return h
		}
	}
	t.Fatalf("must handle endpoint: %v", e)
	return handler.Handler{}
}