Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(46)

Side by Side Diff: client/internal/logdog/butler/streamserver/handshake_test.go

Issue 1429993002: LogDog: Add Butler stream server package. (Closed) Base URL: https://github.com/luci/luci-go@logdog-review-butlerproto
Patch Set: Cleanup, comments. Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package streamserver
6
7 import (
8 "bytes"
9 "encoding/binary"
10 "fmt"
11 "io"
12 "testing"
13 "time"
14
15 "github.com/luci/luci-go/client/logdog/butlerlib/streamclient"
16 "github.com/luci/luci-go/client/logdog/butlerlib/streamproto"
17 "github.com/luci/luci-go/common/clock/testclock"
18 "github.com/luci/luci-go/common/logdog/protocol"
19 "github.com/luci/luci-go/common/logdog/types"
20 "github.com/luci/luci-go/common/proto/google"
21 ta "github.com/luci/luci-go/common/testing/assertions"
22 . "github.com/smartystreets/goconvey/convey"
23 "golang.org/x/net/context"
24 )
25
26 func writePanic(w io.Writer, d []byte) {
27 amt, err := w.Write(d)
28 if err != nil {
29 panic(err)
30 }
31 if amt != len(d) {
32 panic("failed to write full buffer")
33 }
34 }
35
36 type handshakeBuilder struct {
37 magic []byte // The frame header. If empty, don't include a frame header .
38 size uint64 // The size. If zero, calculate the size.
39 }
40
41 func (b *handshakeBuilder) writeTo(w io.Writer, handshake string, data []byte) {
42 // Frame header
43 if len(b.magic) > 0 {
44 writePanic(w, b.magic)
45 }
46
47 // Size
48 size := b.size
49 if size == 0 {
50 size = uint64(len(handshake))
51 }
52 sizeBuf := make([]byte, binary.MaxVarintLen64)
53 count := binary.PutUvarint(sizeBuf, uint64(size))
54 writePanic(w, sizeBuf[:count])
55
56 if handshake != "" {
57 writePanic(w, []byte(handshake))
58 }
59 writePanic(w, data)
60 }
61
62 // Generate a reader from the configuration.
63 func (b *handshakeBuilder) reader(handshake string, data []byte) io.Reader {
64 r := bytes.Buffer{}
65 b.writeTo(&r, handshake, data)
66 return &r
67 }
68
69 // Tests for getProtocolFromMagic
70 func TestGetProtocolFromMagic(t *testing.T) {
71 Convey(`Given a Reader that will emit the protocol header.`, t, func() {
72 ctx := context.Background()
73 hb := handshakeBuilder{
74 magic: streamclient.ProtocolFrameHeaderMagic,
75 }
76 dr := hb.reader("", nil)
77
78 Convey(`Should return a protocol object.`, func() {
79 protocol, err := getProtocolFromMagic(ctx, dr)
80 So(err, ShouldBeNil)
81 So(protocol, ShouldHaveSameTypeAs, &handshakeProtocolImp l{})
82 })
83 })
84
85 Convey(`Given a Reader with not enough data.`, t, func() {
86 ctx := context.Background()
87 dr := bytes.NewReader([]byte{})
88
89 Convey(`Should return an error.`, func() {
90 _, err := getProtocolFromMagic(ctx, dr)
91 So(err, ShouldNotBeNil)
92 })
93 })
94
95 Convey(`Given a Reader with invalid protocol data.`, t, func() {
96 ctx := context.Background()
97 dr := bytes.NewReader([]byte{0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA} )
98
99 Convey(`Should return an error.`, func() {
100 _, err := getProtocolFromMagic(ctx, dr)
101 So(err, ShouldNotBeNil)
102 })
103 })
104 }
105
106 // Tests for handshakeProtocol
107 func testHandshakeProtocol(t *testing.T, verbose bool) {
108 Convey(fmt.Sprintf(`A handshakeProtocol instance (verbose=%v)`, verbose) , t, func() {
109 var hb handshakeBuilder
110
111 ctx, tc := testclock.UseTime(context.Background(), testclock.Tes tTimeUTC)
112 p := &handshakeProtocolImpl{}
113 p.forceVerbose = verbose
114
115 Convey(`Loading a handshake frame starting with an invalid size varint value must fail.`, func() {
116 // This exceeds the maximum 64-bit varint size (10 bytes ) and never
117 // terminates (no MSB).
118 _, err := p.Handshake(ctx, bytes.NewReader([]byte{
119 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
120 }))
121 So(err, ShouldNotBeNil)
122 })
123
124 Convey(`Loading a handshake frame larger than the maximum header size must fail.`, func() {
125 hb.size = maxHeaderSize + 1
126 _, err := p.Handshake(ctx, hb.reader("", nil))
127 So(err, ShouldNotBeNil)
128 })
129
130 Convey(`Loading an JSON object with just a name`, func() {
131 props, err := p.Handshake(ctx, hb.reader(`{"name": "test "}`, nil))
132 So(err, ShouldBeNil)
133
134 Convey(`Should produce a valid stream configuration.`, f unc() {
135 So(props, ta.ShouldResembleV, &streamproto.Prope rties{
136 LogStreamDescriptor: protocol.LogStreamD escriptor{
137 Name: "test",
138 Timestamp: google.NewTimestamp (tc.Now()),
139 StreamType: protocol.LogStreamD escriptor_TEXT,
140 ContentType: string(types.Conten tTypeText),
141 },
142 })
143 })
144 })
145
146 Convey(`Loading a fully-specified configuration`, func() {
147 data := `{
148 "name": "test", "tee": "stdout", "timestamp": "2 015-05-07T01:29:51+00:00",
149 "contentType": "text/plain",
150 "tags": {"foo": "bar", "baz": "qux"}
151 }`
152 props, err := p.Handshake(ctx, hb.reader(data, nil))
153 So(err, ShouldBeNil)
154
155 Convey(`Should produce a specific configuration.`, func( ) {
156 So(props, ta.ShouldResembleV, &streamproto.Prope rties{
157 LogStreamDescriptor: protocol.LogStreamD escriptor{
158 Name: "test",
159 ContentType: "text/plain",
160 Timestamp: google.NewTimestamp (time.Date(2015, 05, 07, 1, 29, 51, 0, time.UTC)),
161 Tags: []*protocol.LogStreamDescr iptor_Tag{
162 {Key: "baz", Value: "qux "},
163 {Key: "foo", Value: "bar "},
164 },
165 },
166 Tee: streamproto.TeeStdout,
167 })
168 })
169 })
170
171 Convey(`Loading a (valid) JSON array should fail to load.`, func () {
172 data := `["This is an array!"]`
173 _, err := p.Handshake(ctx, hb.reader(data, nil))
174 So(err, ShouldNotBeNil)
175 })
176
177 Convey(`Loading a JSON descriptor with just a name should succee d.`, func() {
178 data := `{"name": "test"}`
179 props, err := p.Handshake(ctx, hb.reader(data, nil))
180 So(err, ShouldBeNil)
181 So(props, ShouldNotBeNil)
182 })
183
184 Convey(`Loading an empty JSON object with a larger-than-necessar y header size should fail.`, func() {
185 data := `{}`
186 hb.size = uint64(len(data) + 10)
187 _, err := p.Handshake(ctx, hb.reader(data, nil))
188 So(err, ShouldNotBeNil)
189 })
190
191 Convey(`Loading an JSON with an erroneous config should fail.`, func() {
192 data := `{"timestamp": "text-for-some-reason"}`
193 _, err := p.Handshake(ctx, hb.reader(data, nil))
194 So(err, ShouldNotBeNil)
195 })
196
197 Convey(`Loading an invalid JSON descriptor should fail.`, func() {
198 data := `invalid`
199 _, err := p.Handshake(ctx, hb.reader(data, nil))
200 So(err, ShouldNotBeNil)
201 })
202 })
203
204 for idx, v := range []string{"none", "stdout", "stderr", "clearly invali d"} {
205 Convey(fmt.Sprintf(`A protocol with a tee type of: %s`, v), t, f unc() {
206 ctx := context.Background()
207 var hb handshakeBuilder
208 data := fmt.Sprintf(`{
209 "name": "test",
210 "tee": "%s"
211 }`, v)
212 p := &handshakeProtocolImpl{}
213 _, err := p.Handshake(ctx, hb.reader(data, nil))
214 if idx <= 2 {
215 Convey(`Should successfully parse.`, func() {
216 So(err, ShouldBeNil)
217 })
218 } else {
219 Convey(`Should fail to parse.`, func() {
220 So(err, ShouldNotBeNil)
221 })
222 }
223 })
224 }
225 }
226
227 func TestHandshakeProtocol(t *testing.T) {
228 testHandshakeProtocol(t, false)
229 }
230
231 // As an optimization, we buffer data differently for verbose output. This
232 // creates a separate code path that we have to take if logging verbose function
233 // is set.
234 func TestHandshakeProtocolVerbose(t *testing.T) {
235 testHandshakeProtocol(t, true)
236 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698