예제 #1
0
func TestTracingSpanEncoding(t *testing.T) {
	s1 := Span{
		traceID:  1,
		parentID: 2,
		spanID:   3,
		flags:    4,
	}
	// Encoding is: spanid:8 parentid:8 traceid:8 traceflags:1
	// http://tchannel.readthedocs.io/en/latest/protocol/#tracing
	encoded := []byte{
		0, 0, 0, 0, 0, 0, 0, 3, /* spanID */
		0, 0, 0, 0, 0, 0, 0, 2, /* parentID */
		0, 0, 0, 0, 0, 0, 0, 1, /* traceID */
		4, /* flags */
	}

	buf := make([]byte, len(encoded))
	writer := typed.NewWriteBuffer(buf)
	require.NoError(t, s1.write(writer), "Failed to encode span")

	assert.Equal(t, encoded, buf, "Encoded span mismatch")

	var s2 Span
	reader := typed.NewReadBuffer(buf)
	require.NoError(t, s2.read(reader), "Failed to decode span")

	assert.Equal(t, s1, s2, "Roundtrip of span failed")
}
예제 #2
0
// newFragment creates a new fragment for marshaling into
func (w *reqResWriter) newFragment(initial bool, checksum Checksum) (*writableFragment, error) {
	if err := w.mex.ctx.Err(); err != nil {
		return nil, w.failed(GetContextError(err))
	}

	message := w.messageForFragment(initial)

	// Create the frame
	frame := w.conn.framePool.Get()
	frame.Header.ID = w.mex.msgID
	frame.Header.messageType = message.messageType()

	// Write the message into the fragment, reserving flags and checksum bytes
	wbuf := typed.NewWriteBuffer(frame.Payload[:])
	fragment := new(writableFragment)
	fragment.frame = frame
	fragment.flagsRef = wbuf.DeferByte()
	if err := message.write(wbuf); err != nil {
		return nil, err
	}
	wbuf.WriteSingleByte(byte(checksum.TypeCode()))
	fragment.checksumRef = wbuf.DeferBytes(checksum.Size())
	fragment.checksum = checksum
	fragment.contents = wbuf
	return fragment, wbuf.Err()
}
예제 #3
0
// TODO(prashant): Use a small buffer and then flush it when it's full.
func writeHeaders(w io.Writer, headers map[string]string) error {
	// Calculate the size of the buffer that we need.
	size := 2
	for k, v := range headers {
		size += 4 /* size of key/value lengths */
		size += len(k) + len(v)
	}

	buf := make([]byte, size)
	writeBuffer := typed.NewWriteBuffer(buf)
	writeBuffer.WriteUint16(uint16(len(headers)))
	for k, v := range headers {
		writeBuffer.WriteLen16String(k)
		writeBuffer.WriteLen16String(v)
	}

	if err := writeBuffer.Err(); err != nil {
		return err
	}

	// Safety check to ensure the bytes written calculation is correct.
	if writeBuffer.BytesWritten() != size {
		return fmt.Errorf("writeHeaders size calculation wrong, expected to write %v bytes, only wrote %v bytes",
			size, writeBuffer.BytesWritten())
	}

	_, err := writeBuffer.FlushTo(w)
	return err
}
예제 #4
0
// WriteHeaders writes the given key-value pairs using the following encoding:
// len~2 (k~4 v~4)~len
func WriteHeaders(w io.Writer, headers map[string]string) error {
	// TODO(prashant): Since we are not writing length-prefixed data here,
	// we can write out to the buffer, and if it fills up, flush it.
	// Right now, we calculate the size of the required buffer and write it out.

	// Calculate the size of the buffer that we need.
	size := 2
	for k, v := range headers {
		size += 4 /* size of key/value lengths */
		size += len(k) + len(v)
	}

	buf := make([]byte, size)
	writeBuffer := typed.NewWriteBuffer(buf)
	writeBuffer.WriteUint16(uint16(len(headers)))
	for k, v := range headers {
		writeBuffer.WriteLen16String(k)
		writeBuffer.WriteLen16String(v)
	}

	if err := writeBuffer.Err(); err != nil {
		return err
	}

	// Safety check to ensure the bytes written calculation is correct.
	if writeBuffer.BytesWritten() != size {
		return fmt.Errorf(
			"writeHeaders size calculation wrong, expected to write %v bytes, only wrote %v bytes",
			size, writeBuffer.BytesWritten())
	}

	_, err := writeBuffer.FlushTo(w)
	return err
}
예제 #5
0
func (ch fragmentChannel) newFragment(initial bool, checksum Checksum) (*writableFragment, error) {
	wbuf := typed.NewWriteBuffer(make([]byte, testFragmentSize))
	fragment := new(writableFragment)
	fragment.flagsRef = wbuf.DeferByte()
	wbuf.WriteSingleByte(byte(checksum.TypeCode()))
	fragment.checksumRef = wbuf.DeferBytes(checksum.Size())
	fragment.checksum = checksum
	fragment.contents = wbuf
	return fragment, wbuf.Err()
}
예제 #6
0
func (ec SystemErrCode) fakeErrFrame() lazyError {
	f := NewFrame(100)
	fh := FrameHeader{
		size:        uint16(0xFF34),
		messageType: messageTypeError,
		ID:          invalidMessageID,
	}
	f.Header = fh
	fh.write(typed.NewWriteBuffer(f.headerBuffer))

	payload := typed.NewWriteBuffer(f.Payload)
	payload.WriteSingleByte(byte(ec))
	payload.WriteBytes(make([]byte, 25)) // tracing

	msg := ec.String()
	payload.WriteUint16(uint16(len(msg)))
	payload.WriteBytes([]byte(msg))
	return newLazyError(f)
}
예제 #7
0
func (cr testCallReq) req() lazyCallReq {
	// TODO: Constructing a frame is ugly because the initial flags byte is
	// written in reqResWriter instead of callReq. We should instead handle that
	// in callReq, which will allow our tests to be sane.
	f := NewFrame(200)
	fh := fakeHeader()
	f.Header = fh
	fh.write(typed.NewWriteBuffer(f.headerBuffer))

	payload := typed.NewWriteBuffer(f.Payload)
	payload.WriteSingleByte(0)           // flags
	payload.WriteUint32(42)              // TTL
	payload.WriteBytes(make([]byte, 25)) // tracing
	payload.WriteLen8String("bankmoji")  // service

	headers := make(map[string]string)
	if cr&reqHasHeaders != 0 {
		addRandomHeaders(headers)
	}
	if cr&reqHasCaller != 0 {
		headers["cn"] = "fake-caller"
	}
	if cr&reqHasDelegate != 0 {
		headers["rd"] = "fake-delegate"
	}
	if cr&reqHasRoutingKey != 0 {
		headers["rk"] = "fake-routingkey"
	}
	writeHeaders(payload, headers)

	if cr&reqHasChecksum == 0 {
		payload.WriteSingleByte(byte(ChecksumTypeNone)) // checksum type
		// no checksum contents for None
	} else {
		payload.WriteSingleByte(byte(ChecksumTypeCrc32C)) // checksum type
		payload.WriteUint32(0)                            // checksum contents
	}
	payload.WriteLen16String("moneys") // method
	return newLazyCallReq(f)
}
예제 #8
0
func (cr testCallRes) res() lazyCallRes {
	f := NewFrame(100)
	fh := FrameHeader{
		size:        uint16(0xFF34),
		messageType: messageTypeCallRes,
		ID:          0xDEADBEEF,
	}
	f.Header = fh
	fh.write(typed.NewWriteBuffer(f.headerBuffer))

	payload := typed.NewWriteBuffer(f.Payload)

	if cr&resIsContinued == 0 {
		payload.WriteSingleByte(0) // flags
	} else {
		payload.WriteSingleByte(hasMoreFragmentsFlag) // flags
	}

	if cr&resIsOK == 0 {
		payload.WriteSingleByte(1) // code not ok
	} else {
		payload.WriteSingleByte(0) // code ok
	}

	headers := make(map[string]string)
	if cr&resHasHeaders != 0 {
		addRandomHeaders(headers)
	}
	writeHeaders(payload, headers)

	if cr&resHasChecksum == 0 {
		payload.WriteSingleByte(byte(ChecksumTypeNone)) // checksum type
		// No contents for ChecksumTypeNone.
	} else {
		payload.WriteSingleByte(byte(ChecksumTypeCrc32C)) // checksum type
		payload.WriteUint32(0)                            // checksum contents
	}
	payload.WriteUint16(0) // no arg1 for call res
	return newLazyCallRes(f)
}
예제 #9
0
func TestFinishesCallResponses(t *testing.T) {
	tests := []struct {
		msgType      messageType
		flags        byte
		finishesCall bool
	}{
		{messageTypeCallRes, 0x00, true},
		{messageTypeCallRes, 0x01, false},
		{messageTypeCallRes, 0x02, true},
		{messageTypeCallRes, 0x03, false},
		{messageTypeCallRes, 0x04, true},
		{messageTypeCallResContinue, 0x00, true},
		{messageTypeCallResContinue, 0x01, false},
		{messageTypeCallResContinue, 0x02, true},
		{messageTypeCallResContinue, 0x03, false},
		{messageTypeCallResContinue, 0x04, true},
		// By definition, callreq should never terminate an RPC.
		{messageTypeCallReq, 0x00, false},
		{messageTypeCallReq, 0x01, false},
		{messageTypeCallReq, 0x02, false},
		{messageTypeCallReq, 0x03, false},
		{messageTypeCallReq, 0x04, false},
	}
	for _, tt := range tests {
		f := NewFrame(100)
		fh := FrameHeader{
			size:        uint16(0xFF34),
			messageType: tt.msgType,
			ID:          0xDEADBEEF,
		}
		f.Header = fh
		fh.write(typed.NewWriteBuffer(f.headerBuffer))

		payload := typed.NewWriteBuffer(f.Payload)
		payload.WriteSingleByte(tt.flags)
		assert.Equal(t, tt.finishesCall, finishesCall(f), "Wrong isLast for flags %v and message type %v", tt.flags, tt.msgType)
	}
}
예제 #10
0
func TestVarintString(t *testing.T) {
	tests := []string{
		"",
		"short string",
		testutils.RandString(1000),
	}

	for _, tt := range tests {
		buf := make([]byte, 2000)
		wb := typed.NewWriteBuffer(buf)
		writeVarintString(wb, tt)

		rb := typed.NewReadBuffer(buf)
		got := readVarintString(rb)
		assert.Equal(t, tt, got, "Varint string mismatch")
	}
}
예제 #11
0
func TestHeaders(t *testing.T) {
	tests := []http.Header{
		http.Header{},
		http.Header{
			"K1": []string{"K1V1", "K1V2", "K1V3"},
			"K2": []string{"K2V2", "K2V2"},
		},
	}

	for _, tt := range tests {
		buf := make([]byte, 1000)
		wb := typed.NewWriteBuffer(buf)
		writeHeaders(wb, tt)

		newHeaders := make(http.Header)
		rb := typed.NewReadBuffer(buf)
		readHeaders(rb, newHeaders)
		assert.Equal(t, tt, newHeaders, "Headers mismatch")
	}
}