Files
fn-serverless/vendor/google.golang.org/api/gensupport/buffer_test.go
Reed Allman 9eaf824398 add jaeger support, link hot container & req span (#840)
* add jaeger support, link hot container & req span

* adds jaeger support now with FN_JAEGER_URL, there's a simple tutorial in the
operating/metrics.md file now and it's pretty easy to get up and running.
* links a hot request span to a hot container span. when we change this to
sample at a lower ratio we'll need to finagle the hot container span to always
sample or something, otherwise we'll hide that info. at least, since we're
sampling at 100% for now if this is flipped on, can see freeze/unfreeze etc.
if they hit. this is useful for debugging. note that zipkin's exporter does
not follow the link at all, hence jaeger... and they're backed by the Cloud
Empire now (CNCF) so we'll probably use it anyway.

* vendor: add thrift for jaeger
2018-03-13 15:57:12 -07:00

297 lines
7.3 KiB
Go

// Copyright 2015 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gensupport
import (
"bytes"
"io"
"io/ioutil"
"reflect"
"testing"
"testing/iotest"
"google.golang.org/api/googleapi"
)
// getChunkAsString reads a chunk from mb, but does not call Next.
func getChunkAsString(t *testing.T, mb *MediaBuffer) (string, error) {
chunk, _, size, err := mb.Chunk()
buf, e := ioutil.ReadAll(chunk)
if e != nil {
t.Fatalf("Failed reading chunk: %v", e)
}
if size != len(buf) {
t.Fatalf("reported chunk size doesn't match actual chunk size: got: %v; want: %v", size, len(buf))
}
return string(buf), err
}
func TestChunking(t *testing.T) {
type testCase struct {
data string // the data to read from the Reader
finalErr error // error to return after data has been read
chunkSize int
wantChunks []string
}
for _, singleByteReads := range []bool{true, false} {
for _, tc := range []testCase{
{
data: "abcdefg",
finalErr: nil,
chunkSize: 3,
wantChunks: []string{"abc", "def", "g"},
},
{
data: "abcdefg",
finalErr: nil,
chunkSize: 1,
wantChunks: []string{"a", "b", "c", "d", "e", "f", "g"},
},
{
data: "abcdefg",
finalErr: nil,
chunkSize: 7,
wantChunks: []string{"abcdefg"},
},
{
data: "abcdefg",
finalErr: nil,
chunkSize: 8,
wantChunks: []string{"abcdefg"},
},
{
data: "abcdefg",
finalErr: io.ErrUnexpectedEOF,
chunkSize: 3,
wantChunks: []string{"abc", "def", "g"},
},
{
data: "abcdefg",
finalErr: io.ErrUnexpectedEOF,
chunkSize: 8,
wantChunks: []string{"abcdefg"},
},
} {
var r io.Reader = &errReader{buf: []byte(tc.data), err: tc.finalErr}
if singleByteReads {
r = iotest.OneByteReader(r)
}
mb := NewMediaBuffer(r, tc.chunkSize)
var gotErr error
got := []string{}
for {
chunk, err := getChunkAsString(t, mb)
if len(chunk) != 0 {
got = append(got, string(chunk))
}
if err != nil {
gotErr = err
break
}
mb.Next()
}
if !reflect.DeepEqual(got, tc.wantChunks) {
t.Errorf("Failed reading buffer: got: %v; want:%v", got, tc.wantChunks)
}
expectedErr := tc.finalErr
if expectedErr == nil {
expectedErr = io.EOF
}
if gotErr != expectedErr {
t.Errorf("Reading buffer error: got: %v; want: %v", gotErr, expectedErr)
}
}
}
}
func TestChunkCanBeReused(t *testing.T) {
er := &errReader{buf: []byte("abcdefg")}
mb := NewMediaBuffer(er, 3)
// expectChunk reads a chunk and checks that it got what was wanted.
expectChunk := func(want string, wantErr error) {
got, err := getChunkAsString(t, mb)
if err != wantErr {
t.Errorf("error reading buffer: got: %v; want: %v", err, wantErr)
}
if !reflect.DeepEqual(got, want) {
t.Errorf("Failed reading buffer: got: %q; want:%q", got, want)
}
}
expectChunk("abc", nil)
// On second call, should get same chunk again.
expectChunk("abc", nil)
mb.Next()
expectChunk("def", nil)
expectChunk("def", nil)
mb.Next()
expectChunk("g", io.EOF)
expectChunk("g", io.EOF)
mb.Next()
expectChunk("", io.EOF)
}
func TestPos(t *testing.T) {
er := &errReader{buf: []byte("abcdefg")}
mb := NewMediaBuffer(er, 3)
expectChunkAtOffset := func(want int64, wantErr error) {
_, off, _, err := mb.Chunk()
if err != wantErr {
t.Errorf("error reading buffer: got: %v; want: %v", err, wantErr)
}
if got := off; got != want {
t.Errorf("resumable buffer Pos: got: %v; want: %v", got, want)
}
}
// We expect the first chunk to be at offset 0.
expectChunkAtOffset(0, nil)
// Fetching the same chunk should return the same offset.
expectChunkAtOffset(0, nil)
// Calling Next multiple times should only cause off to advance by 3, since off is not advanced until
// the chunk is actually read.
mb.Next()
mb.Next()
expectChunkAtOffset(3, nil)
mb.Next()
// Load the final 1-byte chunk.
expectChunkAtOffset(6, io.EOF)
// Next will advance 1 byte. But there are no more chunks, so off will not increase beyond 7.
mb.Next()
expectChunkAtOffset(7, io.EOF)
mb.Next()
expectChunkAtOffset(7, io.EOF)
}
// bytes.Reader implements both Reader and ReaderAt. The following types
// implement various combinations of Reader, ReaderAt and ContentTyper, by
// wrapping bytes.Reader. All implement at least ReaderAt, so they can be
// passed to ReaderAtToReader. The following table summarizes which types
// implement which interfaces:
//
// ReaderAt Reader ContentTyper
// reader x x
// typerReader x x x
// readerAt x
// typerReaderAt x x
// reader implements Reader, in addition to ReaderAt.
type reader struct {
r *bytes.Reader
}
func (r *reader) ReadAt(b []byte, off int64) (n int, err error) {
return r.r.ReadAt(b, off)
}
func (r *reader) Read(b []byte) (n int, err error) {
return r.r.Read(b)
}
// typerReader implements Reader and ContentTyper, in addition to ReaderAt.
type typerReader struct {
r *bytes.Reader
}
func (tr *typerReader) ReadAt(b []byte, off int64) (n int, err error) {
return tr.r.ReadAt(b, off)
}
func (tr *typerReader) Read(b []byte) (n int, err error) {
return tr.r.Read(b)
}
func (tr *typerReader) ContentType() string {
return "ctype"
}
// readerAt implements only ReaderAt.
type readerAt struct {
r *bytes.Reader
}
func (ra *readerAt) ReadAt(b []byte, off int64) (n int, err error) {
return ra.r.ReadAt(b, off)
}
// typerReaderAt implements ContentTyper, in addition to ReaderAt.
type typerReaderAt struct {
r *bytes.Reader
}
func (tra *typerReaderAt) ReadAt(b []byte, off int64) (n int, err error) {
return tra.r.ReadAt(b, off)
}
func (tra *typerReaderAt) ContentType() string {
return "ctype"
}
func TestAdapter(t *testing.T) {
data := "abc"
checkConversion := func(to io.Reader, wantTyper bool) {
if _, ok := to.(googleapi.ContentTyper); ok != wantTyper {
t.Errorf("reader implements typer? got: %v; want: %v", ok, wantTyper)
}
if typer, ok := to.(googleapi.ContentTyper); ok && typer.ContentType() != "ctype" {
t.Errorf("content type: got: %s; want: ctype", typer.ContentType())
}
buf, err := ioutil.ReadAll(to)
if err != nil {
t.Errorf("error reading data: %v", err)
return
}
if !bytes.Equal(buf, []byte(data)) {
t.Errorf("failed reading data: got: %s; want: %s", buf, data)
}
}
type testCase struct {
from io.ReaderAt
wantTyper bool
}
for _, tc := range []testCase{
{
from: &reader{bytes.NewReader([]byte(data))},
wantTyper: false,
},
{
// Reader and ContentTyper
from: &typerReader{bytes.NewReader([]byte(data))},
wantTyper: true,
},
{
// ReaderAt
from: &readerAt{bytes.NewReader([]byte(data))},
wantTyper: false,
},
{
// ReaderAt and ContentTyper
from: &typerReaderAt{bytes.NewReader([]byte(data))},
wantTyper: true,
},
} {
to := ReaderAtToReader(tc.from, int64(len(data)))
checkConversion(to, tc.wantTyper)
// tc.from is a ReaderAt, and should be treated like one, even
// if it also implements Reader. Specifically, it can be
// reused and read from the beginning.
to = ReaderAtToReader(tc.from, int64(len(data)))
checkConversion(to, tc.wantTyper)
}
}