1 0f5f58bb 2016-11-16 stephen.d package p9p
3 0f5f58bb 2016-11-16 stephen.d import (
5 0f5f58bb 2016-11-16 stephen.d "context"
6 0f5f58bb 2016-11-16 stephen.d "encoding/binary"
8 0f5f58bb 2016-11-16 stephen.d "testing"
12 0f5f58bb 2016-11-16 stephen.d // TestTwriteOverflow ensures that a Twrite message will have the data field
13 0f5f58bb 2016-11-16 stephen.d // truncated if the msize would be exceeded.
14 0f5f58bb 2016-11-16 stephen.d func TestTwriteOverflow(t *testing.T) {
15 0f5f58bb 2016-11-16 stephen.d const (
16 0f5f58bb 2016-11-16 stephen.d msize = 512
18 0f5f58bb 2016-11-16 stephen.d // size[4] Twrite tag[2] fid[4] offset[8] count[4] data[count] | count = 0
19 0f5f58bb 2016-11-16 stephen.d overhead = 4 + 1 + 2 + 4 + 8 + 4
23 0f5f58bb 2016-11-16 stephen.d ctx = context.Background()
24 0f5f58bb 2016-11-16 stephen.d conn = &mockConn{}
25 0f5f58bb 2016-11-16 stephen.d ch = NewChannel(conn, msize)
28 0f5f58bb 2016-11-16 stephen.d for _, testcase := range []struct {
29 0f5f58bb 2016-11-16 stephen.d name string
30 0f5f58bb 2016-11-16 stephen.d overflow int // amount to overflow the message by.
33 0f5f58bb 2016-11-16 stephen.d name: "BoundedOverflow",
34 0f5f58bb 2016-11-16 stephen.d overflow: msize / 2,
37 0f5f58bb 2016-11-16 stephen.d name: "LargeOverflow",
38 0f5f58bb 2016-11-16 stephen.d overflow: msize * 3,
41 0f5f58bb 2016-11-16 stephen.d name: "HeaderOverflow",
42 0f5f58bb 2016-11-16 stephen.d overflow: overhead,
45 0f5f58bb 2016-11-16 stephen.d name: "HeaderOffsetOverflow",
46 0f5f58bb 2016-11-16 stephen.d overflow: overhead - 1,
49 0f5f58bb 2016-11-16 stephen.d name: "OverflowByOne",
50 0f5f58bb 2016-11-16 stephen.d overflow: 1,
54 0f5f58bb 2016-11-16 stephen.d t.Run(testcase.name, func(t *testing.T) {
56 0f5f58bb 2016-11-16 stephen.d fcall = overflowMessage(ch.(*channel).codec, msize, testcase.overflow)
57 0f5f58bb 2016-11-16 stephen.d data = fcall.Message.(MessageTwrite).Data
58 0f5f58bb 2016-11-16 stephen.d size uint32
61 0f5f58bb 2016-11-16 stephen.d t.Logf("overflow: %v, len(data): %v, expected overflow: %v", testcase.overflow, len(data), overhead+len(data)-msize)
62 0f5f58bb 2016-11-16 stephen.d conn.buf.Reset()
63 0f5f58bb 2016-11-16 stephen.d if err := ch.WriteFcall(ctx, fcall); err != nil {
64 0f5f58bb 2016-11-16 stephen.d t.Fatal(err)
67 0f5f58bb 2016-11-16 stephen.d if err := binary.Read(bytes.NewReader(conn.buf.Bytes()), binary.LittleEndian, &size); err != nil {
68 0f5f58bb 2016-11-16 stephen.d t.Fatal(err)
71 0f5f58bb 2016-11-16 stephen.d if size != msize {
72 0f5f58bb 2016-11-16 stephen.d t.Fatalf("should have truncated size header: %d != %d", size, msize)
75 0f5f58bb 2016-11-16 stephen.d if conn.buf.Len() != msize {
76 0f5f58bb 2016-11-16 stephen.d t.Fatalf("should have truncated message: conn.buf.Len(%v) != msize(%v)", conn.buf.Len(), msize)
83 0f5f58bb 2016-11-16 stephen.d // TestWriteOverflowError ensures that we return an error in cases when there
84 0f5f58bb 2016-11-16 stephen.d // will certainly be an overflow and it cannot be resolved.
85 0f5f58bb 2016-11-16 stephen.d func TestWriteOverflowError(t *testing.T) {
86 0f5f58bb 2016-11-16 stephen.d const (
87 0f5f58bb 2016-11-16 stephen.d msize = 4
88 0f5f58bb 2016-11-16 stephen.d overflowMSize = msize + 1
92 0f5f58bb 2016-11-16 stephen.d ctx = context.Background()
93 0f5f58bb 2016-11-16 stephen.d conn = &mockConn{}
94 0f5f58bb 2016-11-16 stephen.d ch = NewChannel(conn, msize)
95 0f5f58bb 2016-11-16 stephen.d data = bytes.Repeat([]byte{'A'}, 4)
96 0f5f58bb 2016-11-16 stephen.d fcall = newFcall(1, MessageTwrite{
97 0f5f58bb 2016-11-16 stephen.d Data: data,
99 0f5f58bb 2016-11-16 stephen.d messageSize = 4 + ch.(*channel).codec.Size(fcall)
102 0f5f58bb 2016-11-16 stephen.d err := ch.WriteFcall(ctx, fcall)
103 0f5f58bb 2016-11-16 stephen.d if err == nil {
104 0f5f58bb 2016-11-16 stephen.d t.Fatal("error expected when overflowing message")
107 0f5f58bb 2016-11-16 stephen.d if Overflow(err) != messageSize-msize {
108 0f5f58bb 2016-11-16 stephen.d t.Fatalf("overflow should reflect messageSize and msize, %d != %d", Overflow(err), messageSize-msize)
112 0f5f58bb 2016-11-16 stephen.d // TestReadOverflow ensures that messages coming over a network connection do
113 0f5f58bb 2016-11-16 stephen.d // not overflow the msize. Invalid messages will cause `ReadFcall` to return an
114 0f5f58bb 2016-11-16 stephen.d // Overflow error.
115 0f5f58bb 2016-11-16 stephen.d func TestReadFcallOverflow(t *testing.T) {
116 0f5f58bb 2016-11-16 stephen.d const (
117 0f5f58bb 2016-11-16 stephen.d msize = 256
121 0f5f58bb 2016-11-16 stephen.d ctx = context.Background()
122 0f5f58bb 2016-11-16 stephen.d conn = &mockConn{}
123 0f5f58bb 2016-11-16 stephen.d ch = NewChannel(conn, msize)
124 0f5f58bb 2016-11-16 stephen.d codec = ch.(*channel).codec
127 0f5f58bb 2016-11-16 stephen.d for _, testcase := range []struct {
128 0f5f58bb 2016-11-16 stephen.d name string
129 0f5f58bb 2016-11-16 stephen.d overflow int
132 0f5f58bb 2016-11-16 stephen.d name: "OverflowByOne",
133 0f5f58bb 2016-11-16 stephen.d overflow: 1,
136 0f5f58bb 2016-11-16 stephen.d name: "HeaderOverflow",
137 0f5f58bb 2016-11-16 stephen.d overflow: overheadMessage(codec, MessageTwrite{}),
140 0f5f58bb 2016-11-16 stephen.d name: "HeaderOffsetOverflow",
141 0f5f58bb 2016-11-16 stephen.d overflow: overheadMessage(codec, MessageTwrite{}) - 1,
144 0f5f58bb 2016-11-16 stephen.d t.Run(testcase.name, func(t *testing.T) {
145 0f5f58bb 2016-11-16 stephen.d fcall := overflowMessage(codec, msize, testcase.overflow)
147 0f5f58bb 2016-11-16 stephen.d // prepare the raw message
148 0f5f58bb 2016-11-16 stephen.d p, err := ch.(*channel).codec.Marshal(fcall)
149 0f5f58bb 2016-11-16 stephen.d if err != nil {
150 0f5f58bb 2016-11-16 stephen.d t.Fatal(err)
153 0f5f58bb 2016-11-16 stephen.d // "send" the message into the buffer
154 0f5f58bb 2016-11-16 stephen.d // this message is crafted to overflow the read buffer.
155 0f5f58bb 2016-11-16 stephen.d if err := sendmsg(&conn.buf, p); err != nil {
156 0f5f58bb 2016-11-16 stephen.d t.Fatal(err)
159 0f5f58bb 2016-11-16 stephen.d var incoming Fcall
160 0f5f58bb 2016-11-16 stephen.d err = ch.ReadFcall(ctx, &incoming)
161 0f5f58bb 2016-11-16 stephen.d if err == nil {
162 0f5f58bb 2016-11-16 stephen.d t.Fatal("expected error on fcall")
165 0f5f58bb 2016-11-16 stephen.d // sanity check to ensure our test code has the right overflow
166 0f5f58bb 2016-11-16 stephen.d if testcase.overflow != ch.(*channel).msgmsize(fcall)-msize {
167 0f5f58bb 2016-11-16 stephen.d t.Fatalf("overflow calculation incorrect: %v != %v", testcase.overflow, ch.(*channel).msgmsize(fcall)-msize)
170 0f5f58bb 2016-11-16 stephen.d if Overflow(err) != testcase.overflow {
171 0f5f58bb 2016-11-16 stephen.d t.Fatalf("unexpected overflow on error: %v !=%v", Overflow(err), testcase.overflow)
177 0f5f58bb 2016-11-16 stephen.d // TestTreadRewrite ensures that messages that whose response would overflow
178 0f5f58bb 2016-11-16 stephen.d // the msize will have be adjusted before sending.
179 0f5f58bb 2016-11-16 stephen.d func TestTreadRewrite(t *testing.T) {
180 0f5f58bb 2016-11-16 stephen.d const (
181 0f5f58bb 2016-11-16 stephen.d msize = 256
182 0f5f58bb 2016-11-16 stephen.d overflowMSize = msize + 1
186 0f5f58bb 2016-11-16 stephen.d ctx = context.Background()
187 0f5f58bb 2016-11-16 stephen.d conn = &mockConn{}
188 0f5f58bb 2016-11-16 stephen.d ch = NewChannel(conn, msize)
189 0f5f58bb 2016-11-16 stephen.d buf = make([]byte, overflowMSize)
190 0f5f58bb 2016-11-16 stephen.d // data = bytes.Repeat([]byte{'A'}, overflowMSize)
191 0f5f58bb 2016-11-16 stephen.d fcall = newFcall(1, MessageTread{
192 0f5f58bb 2016-11-16 stephen.d Count: overflowMSize,
194 0f5f58bb 2016-11-16 stephen.d responseMSize = ch.(*channel).msgmsize(newFcall(1, MessageRread{
195 0f5f58bb 2016-11-16 stephen.d Data: buf,
199 0f5f58bb 2016-11-16 stephen.d if err := ch.WriteFcall(ctx, fcall); err != nil {
200 0f5f58bb 2016-11-16 stephen.d t.Fatal(err)
203 0f5f58bb 2016-11-16 stephen.d // just read the message off the buffer
204 0f5f58bb 2016-11-16 stephen.d n, err := readmsg(&conn.buf, buf)
205 0f5f58bb 2016-11-16 stephen.d if err != nil {
206 0f5f58bb 2016-11-16 stephen.d t.Fatal(err)
209 0f5f58bb 2016-11-16 stephen.d *fcall = Fcall{}
210 0f5f58bb 2016-11-16 stephen.d if err := ch.(*channel).codec.Unmarshal(buf[:n], fcall); err != nil {
211 0f5f58bb 2016-11-16 stephen.d t.Fatal(err)
214 0f5f58bb 2016-11-16 stephen.d tread, ok := fcall.Message.(MessageTread)
215 0f5f58bb 2016-11-16 stephen.d if !ok {
216 0f5f58bb 2016-11-16 stephen.d t.Fatalf("unexpected message: %v", fcall)
219 0f5f58bb 2016-11-16 stephen.d if tread.Count != overflowMSize-(uint32(responseMSize)-msize) {
220 0f5f58bb 2016-11-16 stephen.d t.Fatalf("count not rewritten: %v != %v", tread.Count, overflowMSize-(uint32(responseMSize)-msize))
224 0f5f58bb 2016-11-16 stephen.d type mockConn struct {
225 0f5f58bb 2016-11-16 stephen.d net.Conn
226 0f5f58bb 2016-11-16 stephen.d buf bytes.Buffer
229 0f5f58bb 2016-11-16 stephen.d func (m mockConn) SetWriteDeadline(t time.Time) error { return nil }
230 0f5f58bb 2016-11-16 stephen.d func (m mockConn) SetReadDeadline(t time.Time) error { return nil }
232 0f5f58bb 2016-11-16 stephen.d func (m *mockConn) Write(p []byte) (int, error) {
233 0f5f58bb 2016-11-16 stephen.d return m.buf.Write(p)
236 0f5f58bb 2016-11-16 stephen.d func (m *mockConn) Read(p []byte) (int, error) {
237 0f5f58bb 2016-11-16 stephen.d return m.buf.Read(p)
240 0f5f58bb 2016-11-16 stephen.d func overheadMessage(codec Codec, msg Message) int {
241 0f5f58bb 2016-11-16 stephen.d return 4 + codec.Size(newFcall(1, msg))
244 0f5f58bb 2016-11-16 stephen.d // overflowMessage returns message that overflows the msize by overflow bytes,
245 0f5f58bb 2016-11-16 stephen.d // returning the message size and the fcall.
246 0f5f58bb 2016-11-16 stephen.d func overflowMessage(codec Codec, msize, overflow int) *Fcall {
248 0f5f58bb 2016-11-16 stephen.d overhead = overheadMessage(codec, MessageTwrite{})
249 0f5f58bb 2016-11-16 stephen.d data = bytes.Repeat([]byte{'A'}, (msize-overhead)+overflow)
250 0f5f58bb 2016-11-16 stephen.d fcall = newFcall(1, MessageTwrite{
251 0f5f58bb 2016-11-16 stephen.d Data: data,
255 0f5f58bb 2016-11-16 stephen.d return fcall