| // Copyright 2011 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package fcgi |
| |
| import ( |
| "bytes" |
| "errors" |
| "io" |
| "testing" |
| ) |
| |
| var sizeTests = []struct { |
| size uint32 |
| bytes []byte |
| }{ |
| {0, []byte{0x00}}, |
| {127, []byte{0x7F}}, |
| {128, []byte{0x80, 0x00, 0x00, 0x80}}, |
| {1000, []byte{0x80, 0x00, 0x03, 0xE8}}, |
| {33554431, []byte{0x81, 0xFF, 0xFF, 0xFF}}, |
| } |
| |
| func TestSize(t *testing.T) { |
| b := make([]byte, 4) |
| for i, test := range sizeTests { |
| n := encodeSize(b, test.size) |
| if !bytes.Equal(b[:n], test.bytes) { |
| t.Errorf("%d expected %x, encoded %x", i, test.bytes, b) |
| } |
| size, n := readSize(test.bytes) |
| if size != test.size { |
| t.Errorf("%d expected %d, read %d", i, test.size, size) |
| } |
| if len(test.bytes) != n { |
| t.Errorf("%d did not consume all the bytes", i) |
| } |
| } |
| } |
| |
| var streamTests = []struct { |
| desc string |
| recType recType |
| reqId uint16 |
| content []byte |
| raw []byte |
| }{ |
| {"single record", typeStdout, 1, nil, |
| []byte{1, byte(typeStdout), 0, 1, 0, 0, 0, 0}, |
| }, |
| // this data will have to be split into two records |
| {"two records", typeStdin, 300, make([]byte, 66000), |
| bytes.Join([][]byte{ |
| // header for the first record |
| {1, byte(typeStdin), 0x01, 0x2C, 0xFF, 0xFF, 1, 0}, |
| make([]byte, 65536), |
| // header for the second |
| {1, byte(typeStdin), 0x01, 0x2C, 0x01, 0xD1, 7, 0}, |
| make([]byte, 472), |
| // header for the empty record |
| {1, byte(typeStdin), 0x01, 0x2C, 0, 0, 0, 0}, |
| }, |
| nil), |
| }, |
| } |
| |
| type nilCloser struct { |
| io.ReadWriter |
| } |
| |
| func (c *nilCloser) Close() error { return nil } |
| |
| func TestStreams(t *testing.T) { |
| var rec record |
| outer: |
| for _, test := range streamTests { |
| buf := bytes.NewBuffer(test.raw) |
| var content []byte |
| for buf.Len() > 0 { |
| if err := rec.read(buf); err != nil { |
| t.Errorf("%s: error reading record: %v", test.desc, err) |
| continue outer |
| } |
| content = append(content, rec.content()...) |
| } |
| if rec.h.Type != test.recType { |
| t.Errorf("%s: got type %d expected %d", test.desc, rec.h.Type, test.recType) |
| continue |
| } |
| if rec.h.Id != test.reqId { |
| t.Errorf("%s: got request ID %d expected %d", test.desc, rec.h.Id, test.reqId) |
| continue |
| } |
| if !bytes.Equal(content, test.content) { |
| t.Errorf("%s: read wrong content", test.desc) |
| continue |
| } |
| buf.Reset() |
| c := newConn(&nilCloser{buf}) |
| w := newWriter(c, test.recType, test.reqId) |
| if _, err := w.Write(test.content); err != nil { |
| t.Errorf("%s: error writing record: %v", test.desc, err) |
| continue |
| } |
| if err := w.Close(); err != nil { |
| t.Errorf("%s: error closing stream: %v", test.desc, err) |
| continue |
| } |
| if !bytes.Equal(buf.Bytes(), test.raw) { |
| t.Errorf("%s: wrote wrong content", test.desc) |
| } |
| } |
| } |
| |
| type writeOnlyConn struct { |
| buf []byte |
| } |
| |
| func (c *writeOnlyConn) Write(p []byte) (int, error) { |
| c.buf = append(c.buf, p...) |
| return len(p), nil |
| } |
| |
| func (c *writeOnlyConn) Read(p []byte) (int, error) { |
| return 0, errors.New("conn is write-only") |
| } |
| |
| func (c *writeOnlyConn) Close() error { |
| return nil |
| } |
| |
| func TestGetValues(t *testing.T) { |
| var rec record |
| rec.h.Type = typeGetValues |
| |
| wc := new(writeOnlyConn) |
| c := newChild(wc, nil) |
| err := c.handleRecord(&rec) |
| if err != nil { |
| t.Fatalf("handleRecord: %v", err) |
| } |
| |
| const want = "\x01\n\x00\x00\x00\x12\x06\x00" + |
| "\x0f\x01FCGI_MPXS_CONNS1" + |
| "\x00\x00\x00\x00\x00\x00\x01\n\x00\x00\x00\x00\x00\x00" |
| if got := string(wc.buf); got != want { |
| t.Errorf(" got: %q\nwant: %q\n", got, want) |
| } |
| } |