<commit_before>// Copyright 2014 Volker Dobler.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ht

import (
	"fmt"
	"strings"
	"testing"
	"time"
)

type sampleCheck struct {
	A string
	B *string
	C int
	D *int
	E int64
	F time.Duration
	G []string
	H []int

	N nested
	M []nested
	P interface{}

	X float32
	Y int
	Z int

	privateInt int
	privateStr string
}

// let sampleCheck satisfy Check interface.
func (_ sampleCheck) Execute(t *Test) error { return nil }
func (_ sampleCheck) Prepare() error        { return nil }

type nested struct {
	X string
	Y int
}

func BenchmarkSubstituteVariables(b *testing.B) {
	r := strings.NewReplacer("a", "X", "e", "Y", "o", "Z")
	f := map[int64]int64{99: 77}
	var ck Check
	ck = &Body{Contains: "Hallo", Count: 99}
	for i := 0; i < b.N; i++ {
		f := SubstituteVariables(ck, r, f)
		if _, ok := f.(*Body); !ok {
			b.Fatalf("Bad type %T", f)
		}
	}
}

func TestSubstituteCheckVariables(t *testing.T) {
	r := strings.NewReplacer("a", "X", "e", "Y", "o", "Z")
	var ck Check
	ck = &Body{Contains: "Hallo"}
	f := SubstituteVariables(ck, r, nil)
	if bc, ok := f.(*Body); !ok {
		t.Errorf("Bad type %T", f)
	} else if bc.Contains != "HXllZ" {
		t.Errorf("Got %s", bc.Contains)
	}

	bar := "bar"
	baz := 34
	sample := sampleCheck{
		A: "foo",
		B: &bar,
		C: 56,
		D: &baz,
		E: 12321,
		F: time.Duration(999),
		G: []string{"hallo", "gut", "xyz"},
		H: []int{34, 999, 12321, 31415},
		N: nested{
			X: "zoo",
			Y: 56,
		},
		M: []nested{
			{X: "aa", Y: 34},
			{X: "bb", Y: 33},
		},
		P:          "foo",
		X:          56,
		Y:          731,
		Z:          9348,
		privateInt: 56,
		privateStr: "foo",
	}

	r = strings.NewReplacer("a", "X", "o", "Y")
	g := map[int64]int64{34: 44, 56: 66, 12321: 11, 999: 888}
	s := SubstituteVariables(sample, r, g)
	sc, ok := s.(sampleCheck)
	if !ok {
		t.Fatalf("Bad type %T", s)
	}
	if sc.A != "fYY" || *sc.B != "bXr" || sc.C != 66 || *sc.D != 44 ||
		sc.E != 11 || sc.F != time.Duration(888) {
		t.Fatalf("Got %+v", sc)
	}
	if len(sc.G) != 3 || sc.G[0] != "hXllY" || sc.G[1] != "gut" || sc.G[2] != "xyz" {
		t.Fatalf("Got %+v", sc)
	}

	if len(sc.H) != 4 || sc.H[0] != 44 || sc.H[1] != 888 ||
		sc.H[2] != 11 || sc.H[3] != 31415 {
		t.Fatalf("Got %+v", sc)
	}
	if sc.N.X != "zYY" || sc.N.Y != 66 {
		t.Fatalf("Got %+v", sc)
	}
	if len(sc.M) != 2 || sc.M[0].X != "XX" || sc.M[0].Y != 44 ||
		sc.M[1].X != "bb" || sc.M[1].Y != 33 {
		t.Fatalf("Got %+v", sc)
	}
	if sc.P.(string) != "fYY" {
		t.Fatalf("Got %+v", sc)
	}

	// Unexported stuff gets zeroed.
	if sc.X != 56 || sc.Y != 731 || sc.Z != 9348 || sc.privateInt != 0 || sc.privateStr != "" {
		t.Fatalf("Got %+v", sc)
	}

}

func TestUnmarshalJSON(t *testing.T) {
	j := []byte(`[
{Check: "ResponseTime", Lower: 1.23},
{Check: "Body", Prefix: "BEGIN", Regexp: "foo", Count: 3},
]`)

	cl := CheckList{}
	err := (&cl).UnmarshalJSON(j)
	if err != nil {
		t.Fatalf("Unexpected error: %#v", err)
	}

	if len(cl) != 2 {
		t.Fatalf("Wrong len, got %d", len(cl))
	}

	if rt, ok := cl[0].(*ResponseTime); !ok {
		t.Errorf("Check 0, got %T, %#v", cl[0], cl[0])
	} else {
		if rt.Lower != 1.23*1e9 {
			t.Errorf("Got Lower=%d", rt.Lower)
		}
	}

	if rt, ok := cl[1].(*Body); !ok {
		t.Errorf("Check 1, got %T, %#v", cl[1], cl[1])
	} else {
		if rt.Regexp != "foo" {
			t.Errorf("Got Reqexp=%q", rt.Regexp)
		}
		if rt.Prefix != "BEGIN" {
			t.Errorf("Got Prefix=%q", rt.Prefix)
		}
		ce := rt.Prepare()
		if ce != nil {
			t.Errorf("Unexpected error: %#v", ce)
		}
		if len(rt.re.FindAllString("The foo made foomuh", -1)) != 2 {
			t.Errorf("Got %v", rt.re.FindAllString("The foo made foomuh", -1))
		}
	}
}

// ----------------------------------------------------------------------------
// type TC and runTest: helpers for testing the different checks

type TC struct {
	r Response
	c Check
	e error
}

var someError = fmt.Errorf("any error")

const ms = 1e6

func runTest(t *testing.T, i int, tc TC) {
	tc.r.Body()
	fakeTest := Test{Response: tc.r}
	got := tc.c.Execute(&fakeTest)
	switch {
	case got == nil && tc.e == nil:
		return
	case got != nil && tc.e == nil:
		t.Errorf("%d. %s %v: unexpected error %v",
			i, NameOf(tc.c), tc.c, got)
	case got == nil && tc.e != nil:
		t.Errorf("%d. %s %v: missing error, want %v",
			i, NameOf(tc.c), tc.c, tc.e)
	case got != nil && tc.e != nil:
		_, malformed := got.(MalformedCheck)
		if (tc.e == someError && !malformed) ||
			(tc.e == NotFound && got == NotFound) ||
			(tc.e == FoundForbidden && got == FoundForbidden) {
			return
		}
		switch tc.e.(type) {
		case MalformedCheck:
			if !malformed {
				t.Errorf("%d. %s %v:got \"%v\" of type %T, want MalformedCheck",
					i, NameOf(tc.c), tc.c, got, got)
			}
		default:
			t.Errorf("%d. %s %v: got %T of type \"%v\", want %T",
				i, NameOf(tc.c), tc.c, got, got, tc.e)
		}
	}
}
<commit_msg>Prepare checks during testing<commit_after>// Copyright 2014 Volker Dobler.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ht

import (
	"fmt"
	"strings"
	"testing"
	"time"
)

type sampleCheck struct {
	A string
	B *string
	C int
	D *int
	E int64
	F time.Duration
	G []string
	H []int

	N nested
	M []nested
	P interface{}

	X float32
	Y int
	Z int

	privateInt int
	privateStr string
}

// let sampleCheck satisfy Check interface.
func (_ sampleCheck) Execute(t *Test) error { return nil }
func (_ sampleCheck) Prepare() error        { return nil }

type nested struct {
	X string
	Y int
}

func BenchmarkSubstituteVariables(b *testing.B) {
	r := strings.NewReplacer("a", "X", "e", "Y", "o", "Z")
	f := map[int64]int64{99: 77}
	var ck Check
	ck = &Body{Contains: "Hallo", Count: 99}
	for i := 0; i < b.N; i++ {
		f := SubstituteVariables(ck, r, f)
		if _, ok := f.(*Body); !ok {
			b.Fatalf("Bad type %T", f)
		}
	}
}

func TestSubstituteCheckVariables(t *testing.T) {
	r := strings.NewReplacer("a", "X", "e", "Y", "o", "Z")
	var ck Check
	ck = &Body{Contains: "Hallo"}
	f := SubstituteVariables(ck, r, nil)
	if bc, ok := f.(*Body); !ok {
		t.Errorf("Bad type %T", f)
	} else if bc.Contains != "HXllZ" {
		t.Errorf("Got %s", bc.Contains)
	}

	bar := "bar"
	baz := 34
	sample := sampleCheck{
		A: "foo",
		B: &bar,
		C: 56,
		D: &baz,
		E: 12321,
		F: time.Duration(999),
		G: []string{"hallo", "gut", "xyz"},
		H: []int{34, 999, 12321, 31415},
		N: nested{
			X: "zoo",
			Y: 56,
		},
		M: []nested{
			{X: "aa", Y: 34},
			{X: "bb", Y: 33},
		},
		P:          "foo",
		X:          56,
		Y:          731,
		Z:          9348,
		privateInt: 56,
		privateStr: "foo",
	}

	r = strings.NewReplacer("a", "X", "o", "Y")
	g := map[int64]int64{34: 44, 56: 66, 12321: 11, 999: 888}
	s := SubstituteVariables(sample, r, g)
	sc, ok := s.(sampleCheck)
	if !ok {
		t.Fatalf("Bad type %T", s)
	}
	if sc.A != "fYY" || *sc.B != "bXr" || sc.C != 66 || *sc.D != 44 ||
		sc.E != 11 || sc.F != time.Duration(888) {
		t.Fatalf("Got %+v", sc)
	}
	if len(sc.G) != 3 || sc.G[0] != "hXllY" || sc.G[1] != "gut" || sc.G[2] != "xyz" {
		t.Fatalf("Got %+v", sc)
	}

	if len(sc.H) != 4 || sc.H[0] != 44 || sc.H[1] != 888 ||
		sc.H[2] != 11 || sc.H[3] != 31415 {
		t.Fatalf("Got %+v", sc)
	}
	if sc.N.X != "zYY" || sc.N.Y != 66 {
		t.Fatalf("Got %+v", sc)
	}
	if len(sc.M) != 2 || sc.M[0].X != "XX" || sc.M[0].Y != 44 ||
		sc.M[1].X != "bb" || sc.M[1].Y != 33 {
		t.Fatalf("Got %+v", sc)
	}
	if sc.P.(string) != "fYY" {
		t.Fatalf("Got %+v", sc)
	}

	// Unexported stuff gets zeroed.
	if sc.X != 56 || sc.Y != 731 || sc.Z != 9348 || sc.privateInt != 0 || sc.privateStr != "" {
		t.Fatalf("Got %+v", sc)
	}

}

func TestUnmarshalJSON(t *testing.T) {
	j := []byte(`[
{Check: "ResponseTime", Lower: 1.23},
{Check: "Body", Prefix: "BEGIN", Regexp: "foo", Count: 3},
]`)

	cl := CheckList{}
	err := (&cl).UnmarshalJSON(j)
	if err != nil {
		t.Fatalf("Unexpected error: %#v", err)
	}

	if len(cl) != 2 {
		t.Fatalf("Wrong len, got %d", len(cl))
	}

	if rt, ok := cl[0].(*ResponseTime); !ok {
		t.Errorf("Check 0, got %T, %#v", cl[0], cl[0])
	} else {
		if rt.Lower != 1.23*1e9 {
			t.Errorf("Got Lower=%d", rt.Lower)
		}
	}

	if rt, ok := cl[1].(*Body); !ok {
		t.Errorf("Check 1, got %T, %#v", cl[1], cl[1])
	} else {
		if rt.Regexp != "foo" {
			t.Errorf("Got Reqexp=%q", rt.Regexp)
		}
		if rt.Prefix != "BEGIN" {
			t.Errorf("Got Prefix=%q", rt.Prefix)
		}
		ce := rt.Prepare()
		if ce != nil {
			t.Errorf("Unexpected error: %#v", ce)
		}
		if len(rt.re.FindAllString("The foo made foomuh", -1)) != 2 {
			t.Errorf("Got %v", rt.re.FindAllString("The foo made foomuh", -1))
		}
	}
}

// ----------------------------------------------------------------------------
// type TC and runTest: helpers for testing the different checks

type TC struct {
	r Response
	c Check
	e error
}

var someError = fmt.Errorf("any error")

const ms = 1e6

func runTest(t *testing.T, i int, tc TC) {
	tc.r.Body()
	fakeTest := Test{Response: tc.r}
	if err := tc.c.Prepare(); err != nil {
		t.Errorf("%d. %s %v: unexpected error during Prepare %v",
			i, NameOf(tc.c), tc.c, err)
	}
	got := tc.c.Execute(&fakeTest)
	switch {
	case got == nil && tc.e == nil:
		return
	case got != nil && tc.e == nil:
		t.Errorf("%d. %s %v: unexpected error %v",
			i, NameOf(tc.c), tc.c, got)
	case got == nil && tc.e != nil:
		t.Errorf("%d. %s %v: missing error, want %v",
			i, NameOf(tc.c), tc.c, tc.e)
	case got != nil && tc.e != nil:
		_, malformed := got.(MalformedCheck)
		if (tc.e == someError && !malformed) ||
			(tc.e == NotFound && got == NotFound) ||
			(tc.e == FoundForbidden && got == FoundForbidden) {
			return
		}
		switch tc.e.(type) {
		case MalformedCheck:
			if !malformed {
				t.Errorf("%d. %s %v:got \"%v\" of type %T, want MalformedCheck",
					i, NameOf(tc.c), tc.c, got, got)
			}
		default:
			t.Errorf("%d. %s %v: got %T of type \"%v\", want %T",
				i, NameOf(tc.c), tc.c, got, got, tc.e)
		}
	}
}
<|endoftext|>


<commit_before>package GoHPACK

import (
	"github.com/ami-GS/GoHPACK/huffman"
)

func PackIntRepresentation(I uint32, N byte) (buf []byte) {
	if I < uint32(1<<N)-1 {
		return []byte{byte(I)}
	}

	I -= uint32(1<<N) - 1
	var i int = 1
	tmpI := I
	for ; tmpI >= 128; i++ {
		tmpI = tmpI >> 7
	} // check length

	buf = make([]byte, i+1)
	buf[0] = byte(1<<N) - 1
	i = 1
	for ; I >= 0x80; i++ {
		buf[i] = (byte(I) & 0x7f) | 0x80
		I = I >> 7
	}
	buf[i] = byte(I)

	return buf

}

func PackContent(content string, toHuffman bool) []byte {
	if len(content) == 0 {
		if toHuffman {
			return []byte{0x80}
		}
		return []byte{0x00}
	}

	var Wire []byte
	if toHuffman {

		encoded, length := huffman.Root.Encode(content)
		intRep := PackIntRepresentation(uint32(length), 7)
		intRep[0] |= 0x80

		//Wire += hex.EncodeToString(*intRep) + strings.Trim(hex.EncodeToString(b), "00") // + encoded
		return append(append(Wire, intRep...), encoded...)
	}

	intRep := PackIntRepresentation(uint32(len(content)), 7)
	return append(append(Wire, intRep...), []byte(content)...)
}

func Encode(Headers []Header, fromStaticTable, fromDynamicTable, toHuffman bool, table *Table, dynamicTableSize int) (Wire []byte) {
	if dynamicTableSize != -1 {
		intRep := PackIntRepresentation(uint32(dynamicTableSize), 5)
		intRep[0] |= 0x20
		Wire = intRep
	}

	for _, header := range Headers {
		match, index := table.FindHeader(header)
		if fromStaticTable && match {
			var indexLen byte = 4
			var mask byte = 0x00
			var content []byte
			if fromDynamicTable {
				indexLen = 7
				mask = 0x80
				content = []byte{}
			} else {
				content = PackContent(header.Value, toHuffman)
			}
			intRep := PackIntRepresentation(uint32(index), indexLen)
			intRep[0] |= mask
			Wire = append(append(Wire, intRep...), content...)
		} else if fromStaticTable && !match && index > 0 {
			var indexLen byte = 4
			var mask byte = 0x00
			if fromDynamicTable {
				indexLen = 6
				mask = 0x40
				table.AddHeader(header)
			}
			intRep := PackIntRepresentation(uint32(index), indexLen)
			intRep[0] |= mask
			Wire = append(append(Wire, intRep...), PackContent(header.Value, toHuffman)...)
		} else {
			var prefix []byte = []byte{0x00}
			if fromDynamicTable {
				prefix = []byte{0x40}
				table.AddHeader(header)
			}
			content := append(PackContent(header.Name, toHuffman), PackContent(header.Value, toHuffman)...)
			Wire = append(append(Wire, prefix...), content...)
		}
	}

	return
}

func ParseIntRepresentation(buf []byte, N byte) (I, cursor uint32) {
	I = uint32(buf[0] & ((1 << N) - 1)) // byte could be used as byte
	cursor = 1
	if I < ((1 << N) - 1) {
		return I, cursor
	}

	var M byte = 0
	for (buf[cursor] & 0x80) > 0 {
		I += uint32(buf[cursor]&0x7f) * (1 << M)
		M += 7
		cursor += 1
	}
	I += uint32(buf[cursor]&0x7f) * (1 << M)
	return I, cursor + 1

}

func ParseFromByte(buf []byte) (content string, cursor uint32) {
	length, cursor := ParseIntRepresentation(buf, 7)

	if buf[0]&0x80 > 0 {
		content = huffman.Root.Decode(buf[cursor:], length)
	} else {
		content = string(buf[cursor : cursor+length])
	}

	cursor += length
	return
}

func ParseHeader(index uint32, buf []byte, isIndexed bool, table *Table) (name, value string, cursor uint32) {
	if c := uint32(0); !isIndexed {
		if index == 0 {
			name, c = ParseFromByte(buf[cursor:])
			cursor += c
		}
		value, c = ParseFromByte(buf[cursor:])
		cursor += c
	}

	if index > 0 {
		header := table.GetHeader(index)

		name = header.Name
		if len(value) == 0 {
			value = header.Value
		}
	}
	return
}

func Decode(buf []byte, table *Table) (Headers []Header) {
	var cursor uint32 = 0
	for cursor < uint32(len(buf)) {
		isIndexed := false
		isIncremental := false
		var index, c uint32
		if buf[cursor]&0xe0 == 0x20 {
			// 7.3 Header Table Size Update
			size, c := ParseIntRepresentation(buf[cursor:], 5)
			table.SetDynamicTableSize(size)
			cursor += c
		}

		if (buf[cursor] & 0x80) > 0 {
			// 7.1 Indexed Header Field
			if (buf[cursor] & 0x7f) == 0 {
				panic('a')
			}
			index, c = ParseIntRepresentation(buf[cursor:], 7)
			isIndexed = true
		} else {
			if buf[cursor]&0xc0 == 0x40 {
				// 7.2.1 Literal Header Field with Incremental Indexing
				index, c = ParseIntRepresentation(buf[cursor:], 6)
				isIncremental = true
			} else if buf[cursor]&0xf0 == 0xf0 {
				// 7.2.3 Literal Header Field never Indexed
				index, c = ParseIntRepresentation(buf[cursor:], 4)
			} else {
				// 7.2.2 Literal Header Field without Indexing
				index, c = ParseIntRepresentation(buf[cursor:], 4)
			}
		}
		cursor += c

		name, value, c := ParseHeader(index, buf[cursor:], isIndexed, table)
		cursor += c

		header := Header{name, value}
		if isIncremental {
			table.AddHeader(header)
		}
		Headers = append(Headers, header)
	}

	return
}
<commit_msg>improve code<commit_after>package GoHPACK

import (
	"github.com/ami-GS/GoHPACK/huffman"
)

func PackIntRepresentation(I uint32, N byte) (buf []byte) {
	if I < uint32(1<<N)-1 {
		return []byte{byte(I)}
	}

	I -= uint32(1<<N) - 1
	var i int = 1
	tmpI := I
	for ; tmpI >= 128; i++ {
		tmpI = tmpI >> 7
	} // check length

	buf = make([]byte, i+1)
	buf[0] = byte(1<<N) - 1
	i = 1
	for ; I >= 0x80; i++ {
		buf[i] = (byte(I) & 0x7f) | 0x80
		I = I >> 7
	}
	buf[i] = byte(I)

	return buf

}

func PackContent(content string, toHuffman bool) []byte {
	if len(content) == 0 {
		if toHuffman {
			return []byte{0x80}
		}
		return []byte{0x00}
	}

	var Wire []byte
	if toHuffman {

		encoded, length := huffman.Root.Encode(content)
		intRep := PackIntRepresentation(uint32(length), 7)
		intRep[0] |= 0x80

		//Wire += hex.EncodeToString(*intRep) + strings.Trim(hex.EncodeToString(b), "00") // + encoded
		return append(append(Wire, intRep...), encoded...)
	}

	intRep := PackIntRepresentation(uint32(len(content)), 7)
	return append(append(Wire, intRep...), []byte(content)...)
}

func Encode(Headers []Header, fromStaticTable, fromDynamicTable, toHuffman bool, table *Table, dynamicTableSize int) (Wire []byte) {
	if dynamicTableSize != -1 {
		intRep := PackIntRepresentation(uint32(dynamicTableSize), 5)
		intRep[0] |= 0x20
		Wire = intRep
	}

	for _, header := range Headers {
		match, index := table.FindHeader(header)
		if fromStaticTable && match {
			var indexLen byte = 4
			var mask byte = 0x00
			var content []byte
			if fromDynamicTable {
				indexLen = 7
				mask = 0x80
				content = []byte{}
			} else {
				content = PackContent(header.Value, toHuffman)
			}
			intRep := PackIntRepresentation(uint32(index), indexLen)
			intRep[0] |= mask
			Wire = append(append(Wire, intRep...), content...)
		} else if fromStaticTable && !match && index > 0 {
			var indexLen byte = 4
			var mask byte = 0x00
			if fromDynamicTable {
				indexLen = 6
				mask = 0x40
				table.AddHeader(header)
			}
			intRep := PackIntRepresentation(uint32(index), indexLen)
			intRep[0] |= mask
			Wire = append(append(Wire, intRep...), PackContent(header.Value, toHuffman)...)
		} else {
			var prefix byte = 0x00
			if fromDynamicTable {
				prefix = 0x40
				table.AddHeader(header)
			}
			content := append(PackContent(header.Name, toHuffman), PackContent(header.Value, toHuffman)...)
			Wire = append(append(Wire, prefix), content...)
		}
	}

	return
}

func ParseIntRepresentation(buf []byte, N byte) (I, cursor uint32) {
	I = uint32(buf[0] & ((1 << N) - 1)) // byte could be used as byte
	cursor = 1
	if I < ((1 << N) - 1) {
		return I, cursor
	}

	var M byte = 0
	for (buf[cursor] & 0x80) > 0 {
		I += uint32(buf[cursor]&0x7f) * (1 << M)
		M += 7
		cursor += 1
	}
	I += uint32(buf[cursor]&0x7f) * (1 << M)
	return I, cursor + 1

}

func ParseFromByte(buf []byte) (content string, cursor uint32) {
	length, cursor := ParseIntRepresentation(buf, 7)

	if buf[0]&0x80 > 0 {
		content = huffman.Root.Decode(buf[cursor:], length)
	} else {
		content = string(buf[cursor : cursor+length])
	}

	cursor += length
	return
}

func ParseHeader(index uint32, buf []byte, isIndexed bool, table *Table) (name, value string, cursor uint32) {
	if c := uint32(0); !isIndexed {
		if index == 0 {
			name, c = ParseFromByte(buf[cursor:])
			cursor += c
		}
		value, c = ParseFromByte(buf[cursor:])
		cursor += c
	}

	if index > 0 {
		header := table.GetHeader(index)

		name = header.Name
		if len(value) == 0 {
			value = header.Value
		}
	}
	return
}

func Decode(buf []byte, table *Table) (Headers []Header) {
	var cursor uint32 = 0
	for cursor < uint32(len(buf)) {
		isIndexed := false
		isIncremental := false
		var index, c uint32
		if buf[cursor]&0xe0 == 0x20 {
			// 7.3 Header Table Size Update
			size, c := ParseIntRepresentation(buf[cursor:], 5)
			table.SetDynamicTableSize(size)
			cursor += c
		}

		if (buf[cursor] & 0x80) > 0 {
			// 7.1 Indexed Header Field
			if (buf[cursor] & 0x7f) == 0 {
				panic('a')
			}
			index, c = ParseIntRepresentation(buf[cursor:], 7)
			isIndexed = true
		} else {
			if buf[cursor]&0xc0 == 0x40 {
				// 7.2.1 Literal Header Field with Incremental Indexing
				index, c = ParseIntRepresentation(buf[cursor:], 6)
				isIncremental = true
			} else if buf[cursor]&0xf0 == 0xf0 {
				// 7.2.3 Literal Header Field never Indexed
				index, c = ParseIntRepresentation(buf[cursor:], 4)
			} else {
				// 7.2.2 Literal Header Field without Indexing
				index, c = ParseIntRepresentation(buf[cursor:], 4)
			}
		}
		cursor += c

		name, value, c := ParseHeader(index, buf[cursor:], isIndexed, table)
		cursor += c

		header := Header{name, value}
		if isIncremental {
			table.AddHeader(header)
		}
		Headers = append(Headers, header)
	}

	return
}
<|endoftext|>


<commit_before>package clc

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
)

type Client struct {
	config *Config
	client *http.Client
	token  Token
}

func New(config *Config) *Client {
	return &Client{
		config: config,
		client: http.DefaultClient,
	}
}

func (c *Client) Auth() (string, error) {
	url := `https://api.ctl.io/v2/authentication/login`
	body := []byte(fmt.Sprintf(`{"username":"%s", "password":"%s"}`, c.config.Name, c.config.Password))
	req, err := http.NewRequest("POST", url, ioutil.NopCloser(bytes.NewReader(body)))
	if err != nil {
		return "", err
	}
	req.Header.Add("Content-Type", "application/json")
	resp, err := c.client.Do(req)
	if err != nil {
		return "", err
	}
	if err := json.NewDecoder(resp.Body).Decode(&c.token); err != nil {
		return "", err
	}
	return c.token.Token, nil
}

type Token struct {
	Token string `json:"bearerToken"`
}

type Config struct {
	Name     string
	Password string
	Alias    string
}

func EnvConfig() (*Config, error) {
	user := os.Getenv("CLC_USERNAME")
	if user == "" {
		return nil, errors.New("Please set CLC_USERNAME")
	}
	pw := os.Getenv("CLC_PASSWORD")
	if pw == "" {
		return nil, errors.New("Please set CLC_PASSWORD")
	}

	return &Config{
		Name:     user,
		Password: pw,
	}, nil
}
<commit_msg>client will own baseURL<commit_after>package clc

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
)

type Client struct {
	config  *Config
	client  *http.Client
	token   Token
	baseURL string
}

func New(config *Config) *Client {
	return &Client{
		config:  config,
		client:  http.DefaultClient,
		baseURL: "https://api.ctl.io/v2",
	}
}

func (c *Client) Auth() (string, error) {
	url := `https://api.ctl.io/v2/authentication/login`
	body := []byte(fmt.Sprintf(`{"username":"%s", "password":"%s"}`, c.config.Name, c.config.Password))
	req, err := http.NewRequest("POST", url, ioutil.NopCloser(bytes.NewReader(body)))
	if err != nil {
		return "", err
	}
	req.Header.Add("Content-Type", "application/json")
	resp, err := c.client.Do(req)
	if err != nil {
		return "", err
	}
	if err := json.NewDecoder(resp.Body).Decode(&c.token); err != nil {
		return "", err
	}
	return c.token.Token, nil
}

type Token struct {
	Token string `json:"bearerToken"`
}

type Config struct {
	Name     string
	Password string
	Alias    string
}

func EnvConfig() (*Config, error) {
	user := os.Getenv("CLC_USERNAME")
	if user == "" {
		return nil, errors.New("Please set CLC_USERNAME")
	}
	pw := os.Getenv("CLC_PASSWORD")
	if pw == "" {
		return nil, errors.New("Please set CLC_PASSWORD")
	}

	return &Config{
		Name:     user,
		Password: pw,
	}, nil
}
<|endoftext|>


<commit_before>package client

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/url"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/hyperhq/hyper/engine"
	"github.com/hyperhq/hyper/lib/docker/pkg/namesgenerator"
	"github.com/hyperhq/hyper/utils"
	"github.com/hyperhq/runv/hypervisor/pod"

	gflag "github.com/jessevdk/go-flags"
)

// hyper run [OPTIONS] image [COMMAND] [ARGS...]
func (cli *HyperClient) HyperCmdRun(args ...string) error {
	if len(args) == 0 {
		return fmt.Errorf("%s ERROR: Can not accept the 'run' command without argument!\n", os.Args[0])
	}
	var opts struct {
		PodFile       string   `short:"p" long:"podfile" value-name:"\"\"" description:"Create and Run a pod based on the pod file"`
		K8s           string   `short:"k" long:"kubernetes" value-name:"\"\"" description:"Create and Run a pod based on the kubernetes pod file"`
		Yaml          bool     `short:"y" long:"yaml" default:"false" default-mask:"-" description:"Create a pod based on Yaml file"`
		Name          string   `long:"name" value-name:"\"\"" description:"Assign a name to the container"`
		Attach        bool     `short:"a" long:"attach" default:"false" default-mask:"-" description:"(from podfile) Attach the stdin, stdout and stderr to the container"`
		Detach        bool     `short:"d" long:"detach" default:"false" default-mask:"-" description:"(from cmdline) Not Attach the stdin, stdout and stderr to the container"`
		Workdir       string   `long:"workdir" default:"/" value-name:"\"\"" default-mask:"-" description:"Working directory inside the container"`
		Tty           bool     `short:"t" long:"tty" default:"false" default-mask:"-" description:"the run command in tty, such as bash shell"`
		Cpu           int      `long:"cpu" default:"1" value-name:"1" default-mask:"-" description:"CPU number for the VM"`
		Memory        int      `long:"memory" default:"128" value-name:"128" default-mask:"-" description:"Memory size (MB) for the VM"`
		Env           []string `long:"env" value-name:"[]" default-mask:"-" description:"Set environment variables"`
		EntryPoint    string   `long:"entrypoint" value-name:"\"\"" default-mask:"-" description:"Overwrite the default ENTRYPOINT of the image"`
		RestartPolicy string   `long:"restart" default:"never" value-name:"\"\"" default-mask:"-" description:"Restart policy to apply when a container exits (never, onFailure, always)"`
		LogDriver     string   `long:"log-driver" value-name:"\"\"" description:"Logging driver for Pod"`
		LogOpts       []string `long:"log-opt" description:"Log driver options"`
		Remove        bool     `long:"rm" default:"false" value-name:"" default-mask:"-" description:"Automatically remove the pod when it exits"`
		Portmap       []string `long:"publish" value-name:"[]" default-mask:"-" description:"Publish a container's port to the host, format: --publish [tcp/udp:]hostPort:containerPort"`
	}

	var parser = gflag.NewParser(&opts, gflag.Default|gflag.IgnoreUnknown)
	parser.Usage = "run [OPTIONS] IMAGE [COMMAND] [ARG...]\n\nCreate a pod, and launch a new VM to run the pod"
	args, err := parser.Parse()
	if err != nil {
		if !strings.Contains(err.Error(), "Usage") {
			return err
		} else {
			return nil
		}
	}

	var (
		podJson string
		attach  bool = false
	)

	if opts.PodFile != "" {
		attach = opts.Attach
		podJson, err = cli.JsonFromFile(opts.PodFile, opts.Yaml, false)
	} else if opts.K8s != "" {
		attach = opts.Attach
		podJson, err = cli.JsonFromFile(opts.K8s, opts.Yaml, false)
	} else {
		if len(args) == 0 {
			return fmt.Errorf("%s: \"run\" requires a minimum of 1 argument, please provide the image.", os.Args[0])
		}
		attach = !opts.Detach
		podJson, err = cli.JsonFromCmdline(args[1:], opts.Env, opts.Portmap, opts.LogDriver, opts.LogOpts,
			opts.Name, opts.Workdir, opts.RestartPolicy, opts.Cpu, opts.Memory, opts.Tty)
	}

	if err != nil {
		return err
	}

	t1 := time.Now()

	podId, err := cli.CreatePod(podJson, opts.Remove)
	if err != nil {
		return err
	}

	fmt.Printf("POD id is %s\n", podId)

	_, err = cli.StartPod(podId, "", attach)
	if err != nil {
		return err
	}

	if !attach {
		t2 := time.Now()
		fmt.Printf("Time to run a POD is %d ms\n", (t2.UnixNano()-t1.UnixNano())/1000000)
	}
	return nil
}

func (cli *HyperClient) JsonFromFile(filename string, yaml, k8s bool) (string, error) {
	if _, err := os.Stat(filename); err != nil {
		return "", err
	}

	jsonbody, err := ioutil.ReadFile(filename)
	if err != nil {
		return "", err
	}

	if yaml == true {
		jsonbody, err = cli.ConvertYamlToJson(jsonbody)
		if err != nil {
			return "", err
		}
	}

	if k8s {
		var kpod pod.KPod

		if err := json.Unmarshal(jsonbody, &kpod); err != nil {
			return "", err
		}
		userpod, err := kpod.Convert()
		if err != nil {
			return "", err
		}
		jsonbody, err = json.Marshal(*userpod)
		if err != nil {
			return "", err
		}
	}

	return string(jsonbody), nil
}

// cmdArgs: args[1:]
func (cli *HyperClient) JsonFromCmdline(cmdArgs, cmdEnvs, cmdPortmaps []string, cmdLogDriver string, cmdLogOpts []string,
	cmdName, cmdWorkdir, cmdRestartPolicy string, cpu, memory int, tty bool) (string, error) {

	var (
		name    = cmdName
		image   = cmdArgs[0]
		command = []string{}
		env     = []pod.UserEnvironmentVar{}
		ports   = []pod.UserContainerPort{}
		logOpts = make(map[string]string)
	)
	if len(cmdArgs) > 1 {
		command = cmdArgs[1:]
	}
	if name == "" {
		name = imageToName(image)
	}
	if memory == 0 {
		memory = 128
	}
	if cpu == 0 {
		cpu = 1
	}
	for _, v := range cmdEnvs {
		if eqlIndex := strings.Index(v, "="); eqlIndex > 0 {
			env = append(env, pod.UserEnvironmentVar{
				Env:   v[:eqlIndex],
				Value: v[eqlIndex+1:],
			})
		}
	}

	for _, v := range cmdLogOpts {
		eql := strings.Index(v, "=")
		if eql > 0 {
			logOpts[v[:eql]] = v[eql+1:]
		} else {
			logOpts[v] = ""
		}
	}

	for _, v := range cmdPortmaps {
		p, err := parsePortMapping(v)
		if err != nil {
			return "", err
		}
		ports = append(ports, *p)
	}

	containerList := []pod.UserContainer{{
		Name:          name,
		Image:         image,
		Command:       command,
		Workdir:       cmdWorkdir,
		Entrypoint:    []string{},
		Ports:         ports,
		Envs:          env,
		Volumes:       []pod.UserVolumeReference{},
		Files:         []pod.UserFileReference{},
		RestartPolicy: cmdRestartPolicy,
	}}

	userPod := &pod.UserPod{
		Name:       name,
		Containers: containerList,
		Resource:   pod.UserResource{Vcpu: cpu, Memory: memory},
		Files:      []pod.UserFile{},
		Volumes:    []pod.UserVolume{},
		LogConfig: pod.PodLogConfig{
			Type:   cmdLogDriver,
			Config: logOpts,
		},
		Tty: tty,
	}

	jsonString, _ := json.Marshal(userPod)
	return string(jsonString), nil
}

func parsePortMapping(portmap string) (*pod.UserContainerPort, error) {

	var (
		port  = pod.UserContainerPort{}
		proto string
		hPort string
		cPort string
		err   error
	)

	fields := strings.Split(portmap, ":")
	if len(fields) < 2 {
		return nil, fmt.Errorf("flag needs host port and container port: --publish")
	} else if len(fields) == 2 {
		proto = "tcp"
		hPort = fields[0]
		cPort = fields[1]
	} else {
		proto = fields[0]
		if proto != "tcp" && proto != "udp" {
			return nil, fmt.Errorf("flag needs protocol(tcp or udp): --publish")
		}
		hPort = fields[1]
		cPort = fields[2]
	}

	port.Protocol = proto
	port.HostPort, err = strconv.Atoi(hPort)
	if err != nil {
		return nil, fmt.Errorf("flag needs host port and container port: --publish: %v", err)
	}
	port.ContainerPort, err = strconv.Atoi(cPort)
	if err != nil {
		return nil, fmt.Errorf("flag needs host port and container port: --publish: %v", err)
	}

	return &port, nil
}

func imageToName(image string) string {
	name := image
	fields := strings.Split(image, "/")
	if len(fields) > 1 {
		name = fields[len(fields)-1]
	}
	fields = strings.Split(name, ":")
	if len(fields) < 2 {
		name = name + "-" + utils.RandStr(10, "number")
	} else {
		name = fields[0] + "-" + fields[1] + "-" + utils.RandStr(10, "number")
	}

	validContainerNameChars := `[a-zA-Z0-9][a-zA-Z0-9_.-]`
	validContainerNamePattern := regexp.MustCompile(`^/?` + validContainerNameChars + `+$`)
	if !validContainerNamePattern.MatchString(name) {
		name = namesgenerator.GetRandomName(0)
	}
	return name
}

func (cli *HyperClient) GetContainerByPod(podId string) (string, error) {
	v := url.Values{}
	v.Set("item", "container")
	v.Set("pod", podId)
	body, _, err := readBody(cli.call("GET", "/list?"+v.Encode(), nil, nil))
	if err != nil {
		return "", err
	}
	out := engine.NewOutput()
	remoteInfo, err := out.AddEnv()
	if err != nil {
		return "", err
	}

	if _, err := out.Write(body); err != nil {
		fmt.Printf("Error reading remote info: %s", err)
		return "", err
	}
	out.Close()
	var containerResponse = []string{}
	containerResponse = remoteInfo.GetList("cData")
	for _, c := range containerResponse {
		fields := strings.Split(c, ":")
		containerId := fields[0]
		if podId == fields[2] {
			return containerId, nil
		}
	}

	return "", fmt.Errorf("Container not found")
}
<commit_msg>fix fail to start kubernetes pod<commit_after>package client

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/url"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/hyperhq/hyper/engine"
	"github.com/hyperhq/hyper/lib/docker/pkg/namesgenerator"
	"github.com/hyperhq/hyper/utils"
	"github.com/hyperhq/runv/hypervisor/pod"

	gflag "github.com/jessevdk/go-flags"
)

// hyper run [OPTIONS] image [COMMAND] [ARGS...]
func (cli *HyperClient) HyperCmdRun(args ...string) error {
	if len(args) == 0 {
		return fmt.Errorf("%s ERROR: Can not accept the 'run' command without argument!\n", os.Args[0])
	}
	var opts struct {
		PodFile       string   `short:"p" long:"podfile" value-name:"\"\"" description:"Create and Run a pod based on the pod file"`
		K8s           string   `short:"k" long:"kubernetes" value-name:"\"\"" description:"Create and Run a pod based on the kubernetes pod file"`
		Yaml          bool     `short:"y" long:"yaml" default:"false" default-mask:"-" description:"Create a pod based on Yaml file"`
		Name          string   `long:"name" value-name:"\"\"" description:"Assign a name to the container"`
		Attach        bool     `short:"a" long:"attach" default:"false" default-mask:"-" description:"(from podfile) Attach the stdin, stdout and stderr to the container"`
		Detach        bool     `short:"d" long:"detach" default:"false" default-mask:"-" description:"(from cmdline) Not Attach the stdin, stdout and stderr to the container"`
		Workdir       string   `long:"workdir" default:"/" value-name:"\"\"" default-mask:"-" description:"Working directory inside the container"`
		Tty           bool     `short:"t" long:"tty" default:"false" default-mask:"-" description:"the run command in tty, such as bash shell"`
		Cpu           int      `long:"cpu" default:"1" value-name:"1" default-mask:"-" description:"CPU number for the VM"`
		Memory        int      `long:"memory" default:"128" value-name:"128" default-mask:"-" description:"Memory size (MB) for the VM"`
		Env           []string `long:"env" value-name:"[]" default-mask:"-" description:"Set environment variables"`
		EntryPoint    string   `long:"entrypoint" value-name:"\"\"" default-mask:"-" description:"Overwrite the default ENTRYPOINT of the image"`
		RestartPolicy string   `long:"restart" default:"never" value-name:"\"\"" default-mask:"-" description:"Restart policy to apply when a container exits (never, onFailure, always)"`
		LogDriver     string   `long:"log-driver" value-name:"\"\"" description:"Logging driver for Pod"`
		LogOpts       []string `long:"log-opt" description:"Log driver options"`
		Remove        bool     `long:"rm" default:"false" value-name:"" default-mask:"-" description:"Automatically remove the pod when it exits"`
		Portmap       []string `long:"publish" value-name:"[]" default-mask:"-" description:"Publish a container's port to the host, format: --publish [tcp/udp:]hostPort:containerPort"`
	}

	var parser = gflag.NewParser(&opts, gflag.Default|gflag.IgnoreUnknown)
	parser.Usage = "run [OPTIONS] IMAGE [COMMAND] [ARG...]\n\nCreate a pod, and launch a new VM to run the pod"
	args, err := parser.Parse()
	if err != nil {
		if !strings.Contains(err.Error(), "Usage") {
			return err
		} else {
			return nil
		}
	}

	var (
		podJson string
		attach  bool = false
	)

	if opts.PodFile != "" {
		attach = opts.Attach
		podJson, err = cli.JsonFromFile(opts.PodFile, opts.Yaml, false)
	} else if opts.K8s != "" {
		attach = opts.Attach
		podJson, err = cli.JsonFromFile(opts.K8s, opts.Yaml, true)
	} else {
		if len(args) == 0 {
			return fmt.Errorf("%s: \"run\" requires a minimum of 1 argument, please provide the image.", os.Args[0])
		}
		attach = !opts.Detach
		podJson, err = cli.JsonFromCmdline(args[1:], opts.Env, opts.Portmap, opts.LogDriver, opts.LogOpts,
			opts.Name, opts.Workdir, opts.RestartPolicy, opts.Cpu, opts.Memory, opts.Tty)
	}

	if err != nil {
		return err
	}

	t1 := time.Now()

	podId, err := cli.CreatePod(podJson, opts.Remove)
	if err != nil {
		return err
	}

	fmt.Printf("POD id is %s\n", podId)

	_, err = cli.StartPod(podId, "", attach)
	if err != nil {
		return err
	}

	if !attach {
		t2 := time.Now()
		fmt.Printf("Time to run a POD is %d ms\n", (t2.UnixNano()-t1.UnixNano())/1000000)
	}
	return nil
}

func (cli *HyperClient) JsonFromFile(filename string, yaml, k8s bool) (string, error) {
	if _, err := os.Stat(filename); err != nil {
		return "", err
	}

	jsonbody, err := ioutil.ReadFile(filename)
	if err != nil {
		return "", err
	}

	if yaml == true {
		jsonbody, err = cli.ConvertYamlToJson(jsonbody)
		if err != nil {
			return "", err
		}
	}

	if k8s {
		var kpod pod.KPod

		if err := json.Unmarshal(jsonbody, &kpod); err != nil {
			return "", err
		}
		userpod, err := kpod.Convert()
		if err != nil {
			return "", err
		}
		jsonbody, err = json.Marshal(*userpod)
		if err != nil {
			return "", err
		}
	}

	return string(jsonbody), nil
}

// cmdArgs: args[1:]
func (cli *HyperClient) JsonFromCmdline(cmdArgs, cmdEnvs, cmdPortmaps []string, cmdLogDriver string, cmdLogOpts []string,
	cmdName, cmdWorkdir, cmdRestartPolicy string, cpu, memory int, tty bool) (string, error) {

	var (
		name    = cmdName
		image   = cmdArgs[0]
		command = []string{}
		env     = []pod.UserEnvironmentVar{}
		ports   = []pod.UserContainerPort{}
		logOpts = make(map[string]string)
	)
	if len(cmdArgs) > 1 {
		command = cmdArgs[1:]
	}
	if name == "" {
		name = imageToName(image)
	}
	if memory == 0 {
		memory = 128
	}
	if cpu == 0 {
		cpu = 1
	}
	for _, v := range cmdEnvs {
		if eqlIndex := strings.Index(v, "="); eqlIndex > 0 {
			env = append(env, pod.UserEnvironmentVar{
				Env:   v[:eqlIndex],
				Value: v[eqlIndex+1:],
			})
		}
	}

	for _, v := range cmdLogOpts {
		eql := strings.Index(v, "=")
		if eql > 0 {
			logOpts[v[:eql]] = v[eql+1:]
		} else {
			logOpts[v] = ""
		}
	}

	for _, v := range cmdPortmaps {
		p, err := parsePortMapping(v)
		if err != nil {
			return "", err
		}
		ports = append(ports, *p)
	}

	containerList := []pod.UserContainer{{
		Name:          name,
		Image:         image,
		Command:       command,
		Workdir:       cmdWorkdir,
		Entrypoint:    []string{},
		Ports:         ports,
		Envs:          env,
		Volumes:       []pod.UserVolumeReference{},
		Files:         []pod.UserFileReference{},
		RestartPolicy: cmdRestartPolicy,
	}}

	userPod := &pod.UserPod{
		Name:       name,
		Containers: containerList,
		Resource:   pod.UserResource{Vcpu: cpu, Memory: memory},
		Files:      []pod.UserFile{},
		Volumes:    []pod.UserVolume{},
		LogConfig: pod.PodLogConfig{
			Type:   cmdLogDriver,
			Config: logOpts,
		},
		Tty: tty,
	}

	jsonString, _ := json.Marshal(userPod)
	return string(jsonString), nil
}

func parsePortMapping(portmap string) (*pod.UserContainerPort, error) {

	var (
		port  = pod.UserContainerPort{}
		proto string
		hPort string
		cPort string
		err   error
	)

	fields := strings.Split(portmap, ":")
	if len(fields) < 2 {
		return nil, fmt.Errorf("flag needs host port and container port: --publish")
	} else if len(fields) == 2 {
		proto = "tcp"
		hPort = fields[0]
		cPort = fields[1]
	} else {
		proto = fields[0]
		if proto != "tcp" && proto != "udp" {
			return nil, fmt.Errorf("flag needs protocol(tcp or udp): --publish")
		}
		hPort = fields[1]
		cPort = fields[2]
	}

	port.Protocol = proto
	port.HostPort, err = strconv.Atoi(hPort)
	if err != nil {
		return nil, fmt.Errorf("flag needs host port and container port: --publish: %v", err)
	}
	port.ContainerPort, err = strconv.Atoi(cPort)
	if err != nil {
		return nil, fmt.Errorf("flag needs host port and container port: --publish: %v", err)
	}

	return &port, nil
}

func imageToName(image string) string {
	name := image
	fields := strings.Split(image, "/")
	if len(fields) > 1 {
		name = fields[len(fields)-1]
	}
	fields = strings.Split(name, ":")
	if len(fields) < 2 {
		name = name + "-" + utils.RandStr(10, "number")
	} else {
		name = fields[0] + "-" + fields[1] + "-" + utils.RandStr(10, "number")
	}

	validContainerNameChars := `[a-zA-Z0-9][a-zA-Z0-9_.-]`
	validContainerNamePattern := regexp.MustCompile(`^/?` + validContainerNameChars + `+$`)
	if !validContainerNamePattern.MatchString(name) {
		name = namesgenerator.GetRandomName(0)
	}
	return name
}

func (cli *HyperClient) GetContainerByPod(podId string) (string, error) {
	v := url.Values{}
	v.Set("item", "container")
	v.Set("pod", podId)
	body, _, err := readBody(cli.call("GET", "/list?"+v.Encode(), nil, nil))
	if err != nil {
		return "", err
	}
	out := engine.NewOutput()
	remoteInfo, err := out.AddEnv()
	if err != nil {
		return "", err
	}

	if _, err := out.Write(body); err != nil {
		fmt.Printf("Error reading remote info: %s", err)
		return "", err
	}
	out.Close()
	var containerResponse = []string{}
	containerResponse = remoteInfo.GetList("cData")
	for _, c := range containerResponse {
		fields := strings.Split(c, ":")
		containerId := fields[0]
		if podId == fields[2] {
			return containerId, nil
		}
	}

	return "", fmt.Errorf("Container not found")
}
<|endoftext|>


<commit_before>package tchannel_test

// Copyright (c) 2015 Uber Technologies, Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

import (
	"math/rand"
	"runtime"
	"sync"
	"testing"
	"time"

	. "github.com/uber/tchannel/golang"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"github.com/uber/tchannel/golang/raw"
	"github.com/uber/tchannel/golang/testutils"
	"golang.org/x/net/context"
)

type channelState struct {
	ch      *Channel
	closeCh chan struct{}
	closed  bool
}

func makeCall(ch *Channel, hostPort, service string) error {
	ctx, cancel := NewContext(time.Second)
	defer cancel()

	_, _, _, err := raw.Call(ctx, ch, hostPort, service, "test", nil, nil)
	return err
}

// TestCloseStress ensures that once a Channel is closed, it cannot be reached.
func TestCloseStress(t *testing.T) {
	CheckStress(t)

	const numHandlers = 5
	handler := &swapper{t}
	var lock sync.RWMutex
	var wg sync.WaitGroup
	var channels []*channelState

	// Start numHandlers servers, and don't close the connections till they are signalled.
	for i := 0; i < numHandlers; i++ {
		wg.Add(1)
		go func() {
			assert.NoError(t, testutils.WithServer(nil, func(ch *Channel, hostPort string) {
				ch.Register(raw.Wrap(handler), "test")

				chState := &channelState{
					ch:      ch,
					closeCh: make(chan struct{}),
				}

				lock.Lock()
				channels = append(channels, chState)
				lock.Unlock()
				wg.Done()

				// Wait for a close signal.
				<-chState.closeCh

				// Lock until the connection is closed.
				lock.Lock()
				chState.closed = true
			}))
			lock.Unlock()
		}()
	}

	// Wait till all the channels have been registered.
	wg.Wait()

	// Start goroutines to make calls until the test has ended.
	testEnded := make(chan struct{})
	for i := 0; i < 10; i++ {
		go func() {
			for {
				select {
				case <-testEnded:
					return
				default:
					// Keep making requests till the test ends.
				}

				// Get 2 random channels and make a call from one to the other.
				lock.RLock()
				chState1 := channels[rand.Intn(len(channels))]
				chState2 := channels[rand.Intn(len(channels))]
				if chState1 == chState2 {
					lock.RUnlock()
					continue
				}

				// Grab a read lock to make sure channels aren't closed while we call.
				ch1Closed := chState1.closed
				ch2Closed := chState2.closed
				err := makeCall(chState1.ch, chState2.ch.PeerInfo().HostPort, chState2.ch.PeerInfo().ServiceName)
				lock.RUnlock()
				if ch1Closed || ch2Closed {
					assert.Error(t, err, "Call from %v to %v should fail", chState1.ch.PeerInfo(), chState2.ch.PeerInfo())
				} else {
					assert.NoError(t, err, "Call from %v to %v should not fail", chState1.ch.PeerInfo(), chState2.ch.PeerInfo())
				}
			}
		}()
	}

	// Kill connections till all of the connections are dead.
	for i := 0; i < numHandlers; i++ {
		time.Sleep(time.Duration(rand.Intn(50)) * time.Millisecond)
		channels[i].closeCh <- struct{}{}
	}
}

type simpleHandler struct {
	t *testing.T
	f func(context.Context, *raw.Args) (*raw.Res, error)
}

func (h simpleHandler) OnError(ctx context.Context, err error) {
	h.t.Errorf("simpleHandler OnError: %v %v", ctx, err)
}

func (h simpleHandler) Handle(ctx context.Context, args *raw.Args) (*raw.Res, error) {
	return h.f(ctx, args)
}

func registerFunc(t *testing.T, ch *Channel, name string,
	f func(ctx context.Context, args *raw.Args) (*raw.Res, error)) {
	ch.Register(raw.Wrap(simpleHandler{t, f}), name)
}

func TestCloseSemantics(t *testing.T) {
	defer testutils.SetTimeout(t, 2*time.Second)()
	ctx, cancel := NewContext(time.Second)
	defer cancel()

	makeServer := func(name string) (*Channel, chan struct{}) {
		ch, err := testutils.NewServer(&testutils.ChannelOpts{ServiceName: name})
		require.NoError(t, err)
		c := make(chan struct{})
		registerFunc(t, ch, "stream", func(ctx context.Context, args *raw.Args) (*raw.Res, error) {
			<-c
			return &raw.Res{}, nil
		})
		registerFunc(t, ch, "call", func(ctx context.Context, args *raw.Args) (*raw.Res, error) {
			return &raw.Res{}, nil
		})
		return ch, c
	}

	newClient := func() *Channel {
		ch, err := testutils.NewClient(&testutils.ChannelOpts{ServiceName: "client"})
		require.NoError(t, err)
		return ch
	}

	call := func(from *Channel, to *Channel) error {
		toPeer := to.PeerInfo()
		_, _, _, err := raw.Call(ctx, from, toPeer.HostPort, toPeer.ServiceName, "call", nil, nil)
		return err
	}

	callStream := func(from *Channel, to *Channel) <-chan struct{} {
		c := make(chan struct{})

		toPeer := to.PeerInfo()
		call, err := from.BeginCall(ctx, toPeer.HostPort, toPeer.ServiceName, "stream", nil)
		require.NoError(t, err)
		require.NoError(t, NewArgWriter(call.Arg2Writer()).Write(nil), "write arg2")
		require.NoError(t, NewArgWriter(call.Arg3Writer()).Write(nil), "write arg3")

		go func() {
			var d []byte
			require.NoError(t, NewArgReader(call.Response().Arg2Reader()).Read(&d), "read arg2 from %v to %v", from.PeerInfo(), to.PeerInfo())
			require.NoError(t, NewArgReader(call.Response().Arg3Reader()).Read(&d), "read arg3")
			c <- struct{}{}
		}()

		return c
	}

	s1, s1C := makeServer("s1")
	s2, s2C := makeServer("s2")

	// Make a call from s1 -> s2, and s2 -> s1
	call1 := callStream(s1, s2)
	call2 := callStream(s2, s1)

	// s1 and s2 are both open, so calls to it should be successful.
	require.NoError(t, call(newClient(), s1))
	require.NoError(t, call(newClient(), s2))
	require.NoError(t, call(s1, s2))
	require.NoError(t, call(s2, s1))

	// Close s1, should no longer be able to call it.
	s1.Close()
	assert.Equal(t, ChannelStartClose, s1.State())
	assert.Error(t, call(newClient(), s1), "closed channel should not accept incoming calls")
	require.NoError(t, call(newClient(), s2))

	// Even an existing connection (e.g. from s2) should fail.
	assert.Equal(t, ErrChannelClosed, call(s2, s1), "closed channel should not accept incoming calls")

	require.NoError(t, call(s1, s2),
		"closed channel with pending incoming calls should allow outgoing calls")

	// Once the incoming connection is drained, outgoing calls should fail.
	s1C <- struct{}{}
	<-call2
	assert.Equal(t, ChannelInboundClosed, s1.State())
	require.Error(t, call(s1, s2),
		"closed channel with no pending incoming calls should not allow outgoing calls")

	// Now the channel should be completely closed as there are no pending connections.
	s2C <- struct{}{}
	<-call1
	assert.Equal(t, ChannelClosed, s1.State())

	//time.Sleep(100 * time.Millisecond)
	VerifyNoBlockedGoroutines(t)
}

func TestCloseSingleChannel(t *testing.T) {
	ctx, cancel := NewContext(time.Second)
	defer cancel()

	ch, err := testutils.NewServer(nil)
	require.NoError(t, err, "NewServer failed")

	var connected sync.WaitGroup
	var completed sync.WaitGroup
	blockCall := make(chan struct{})

	registerFunc(t, ch, "echo", func(ctx context.Context, args *raw.Args) (*raw.Res, error) {
		connected.Done()
		<-blockCall
		return &raw.Res{
			Arg2: args.Arg2,
			Arg3: args.Arg3,
		}, nil
	})

	for i := 0; i < 10; i++ {
		connected.Add(1)
		completed.Add(1)
		go func() {
			peerInfo := ch.PeerInfo()
			_, _, _, err = raw.Call(ctx, ch, peerInfo.HostPort, peerInfo.ServiceName, "echo", nil, nil)
			assert.NoError(t, err, "Call failed")
			completed.Done()
		}()
	}

	// Wait for all calls to connect before triggerring the Close (so they do not fail).
	connected.Wait()
	ch.Close()

	// Unblock the calls, and wait for all the calls to complete.
	close(blockCall)
	completed.Wait()

	// Once all calls are complete, the channel should be closed.
	runtime.Gosched()
	assert.Equal(t, ChannelClosed, ch.State())
	VerifyNoBlockedGoroutines(t)
}

func TestCloseOneSide(t *testing.T) {
	ctx, cancel := NewContext(time.Second)
	defer cancel()

	ch1, err := testutils.NewServer(&testutils.ChannelOpts{ServiceName: "client"})
	ch2, err := testutils.NewServer(&testutils.ChannelOpts{ServiceName: "server"})
	require.NoError(t, err, "NewServer 1 failed")
	require.NoError(t, err, "NewServer 2 failed")

	connected := make(chan struct{})
	completed := make(chan struct{})
	blockCall := make(chan struct{})
	registerFunc(t, ch2, "echo", func(ctx context.Context, args *raw.Args) (*raw.Res, error) {
		connected <- struct{}{}
		<-blockCall
		return &raw.Res{
			Arg2: args.Arg2,
			Arg3: args.Arg3,
		}, nil
	})

	go func() {
		ch2Peer := ch2.PeerInfo()
		_, _, _, err := raw.Call(ctx, ch1, ch2Peer.HostPort, ch2Peer.ServiceName, "echo", nil, nil)
		assert.NoError(t, err, "Call failed")
		completed <- struct{}{}
	}()

	// Wait for connected before calling Close.
	<-connected
	ch1.Close()

	// Now unblock the call and wait for the call to complete.
	close(blockCall)
	<-completed

	// Once the call completes, the channel should be closed.
	runtime.Gosched()
	assert.Equal(t, ChannelClosed, ch1.State())

	// We need to close all open TChannels before verifying blocked goroutines.
	ch2.Close()
	VerifyNoBlockedGoroutines(t)
}
<commit_msg>Fix goroutine leaks in Close tests<commit_after>package tchannel_test

// Copyright (c) 2015 Uber Technologies, Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

import (
	"math/rand"
	"runtime"
	"sync"
	"testing"
	"time"

	. "github.com/uber/tchannel/golang"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"github.com/uber/tchannel/golang/raw"
	"github.com/uber/tchannel/golang/testutils"
	"golang.org/x/net/context"
)

type channelState struct {
	ch      *Channel
	closeCh chan struct{}
	closed  bool
}

func makeCall(ch *Channel, hostPort, service string) error {
	ctx, cancel := NewContext(time.Second)
	defer cancel()

	_, _, _, err := raw.Call(ctx, ch, hostPort, service, "test", nil, nil)
	return err
}

// TestCloseStress ensures that once a Channel is closed, it cannot be reached.
func TestCloseStress(t *testing.T) {
	CheckStress(t)

	const numHandlers = 5
	handler := &swapper{t}
	var lock sync.RWMutex
	var wg sync.WaitGroup
	var channels []*channelState

	// Start numHandlers servers, and don't close the connections till they are signalled.
	for i := 0; i < numHandlers; i++ {
		wg.Add(1)
		go func() {
			assert.NoError(t, testutils.WithServer(nil, func(ch *Channel, hostPort string) {
				ch.Register(raw.Wrap(handler), "test")

				chState := &channelState{
					ch:      ch,
					closeCh: make(chan struct{}),
				}

				lock.Lock()
				channels = append(channels, chState)
				lock.Unlock()
				wg.Done()

				// Wait for a close signal.
				<-chState.closeCh

				// Lock until the connection is closed.
				lock.Lock()
				chState.closed = true
			}))
			lock.Unlock()
		}()
	}

	// Wait till all the channels have been registered.
	wg.Wait()

	// Start goroutines to make calls until the test has ended.
	testEnded := make(chan struct{})
	for i := 0; i < 10; i++ {
		go func() {
			for {
				select {
				case <-testEnded:
					return
				default:
					// Keep making requests till the test ends.
				}

				// Get 2 random channels and make a call from one to the other.
				lock.RLock()
				chState1 := channels[rand.Intn(len(channels))]
				chState2 := channels[rand.Intn(len(channels))]
				if chState1 == chState2 {
					lock.RUnlock()
					continue
				}

				// Grab a read lock to make sure channels aren't closed while we call.
				ch1Closed := chState1.closed
				ch2Closed := chState2.closed
				err := makeCall(chState1.ch, chState2.ch.PeerInfo().HostPort, chState2.ch.PeerInfo().ServiceName)
				lock.RUnlock()
				if ch1Closed || ch2Closed {
					assert.Error(t, err, "Call from %v to %v should fail", chState1.ch.PeerInfo(), chState2.ch.PeerInfo())
				} else {
					assert.NoError(t, err, "Call from %v to %v should not fail", chState1.ch.PeerInfo(), chState2.ch.PeerInfo())
				}
			}
		}()
	}

	// Kill connections till all of the connections are dead.
	for i := 0; i < numHandlers; i++ {
		time.Sleep(time.Duration(rand.Intn(50)) * time.Millisecond)
		channels[i].closeCh <- struct{}{}
	}
}

type simpleHandler struct {
	t *testing.T
	f func(context.Context, *raw.Args) (*raw.Res, error)
}

func (h simpleHandler) OnError(ctx context.Context, err error) {
	h.t.Errorf("simpleHandler OnError: %v %v", ctx, err)
}

func (h simpleHandler) Handle(ctx context.Context, args *raw.Args) (*raw.Res, error) {
	return h.f(ctx, args)
}

func registerFunc(t *testing.T, ch *Channel, name string,
	f func(ctx context.Context, args *raw.Args) (*raw.Res, error)) {
	ch.Register(raw.Wrap(simpleHandler{t, f}), name)
}

func TestCloseSemantics(t *testing.T) {
	defer testutils.SetTimeout(t, 2*time.Second)()
	ctx, cancel := NewContext(time.Second)
	defer cancel()

	makeServer := func(name string) (*Channel, chan struct{}) {
		ch, err := testutils.NewServer(&testutils.ChannelOpts{ServiceName: name})
		require.NoError(t, err)
		c := make(chan struct{})
		registerFunc(t, ch, "stream", func(ctx context.Context, args *raw.Args) (*raw.Res, error) {
			<-c
			return &raw.Res{}, nil
		})
		registerFunc(t, ch, "call", func(ctx context.Context, args *raw.Args) (*raw.Res, error) {
			return &raw.Res{}, nil
		})
		return ch, c
	}

	withNewClient := func(f func(ch *Channel)) {
		ch, err := testutils.NewClient(&testutils.ChannelOpts{ServiceName: "client"})
		require.NoError(t, err)
		f(ch)
		ch.Close()
	}

	call := func(from *Channel, to *Channel) error {
		toPeer := to.PeerInfo()
		_, _, _, err := raw.Call(ctx, from, toPeer.HostPort, toPeer.ServiceName, "call", nil, nil)
		return err
	}

	callStream := func(from *Channel, to *Channel) <-chan struct{} {
		c := make(chan struct{})

		toPeer := to.PeerInfo()
		call, err := from.BeginCall(ctx, toPeer.HostPort, toPeer.ServiceName, "stream", nil)
		require.NoError(t, err)
		require.NoError(t, NewArgWriter(call.Arg2Writer()).Write(nil), "write arg2")
		require.NoError(t, NewArgWriter(call.Arg3Writer()).Write(nil), "write arg3")

		go func() {
			var d []byte
			require.NoError(t, NewArgReader(call.Response().Arg2Reader()).Read(&d), "read arg2 from %v to %v", from.PeerInfo(), to.PeerInfo())
			require.NoError(t, NewArgReader(call.Response().Arg3Reader()).Read(&d), "read arg3")
			c <- struct{}{}
		}()

		return c
	}

	s1, s1C := makeServer("s1")
	s2, s2C := makeServer("s2")

	// Make a call from s1 -> s2, and s2 -> s1
	call1 := callStream(s1, s2)
	call2 := callStream(s2, s1)

	// s1 and s2 are both open, so calls to it should be successful.
	withNewClient(func(ch *Channel) {
		require.NoError(t, call(ch, s1))
		require.NoError(t, call(ch, s2))
	})
	require.NoError(t, call(s1, s2))
	require.NoError(t, call(s2, s1))

	// Close s1, should no longer be able to call it.
	s1.Close()
	assert.Equal(t, ChannelStartClose, s1.State())
	withNewClient(func(ch *Channel) {
		assert.Error(t, call(ch, s1), "closed channel should not accept incoming calls")
		require.NoError(t, call(ch, s2),
			"closed channel with pending incoming calls should allow outgoing calls")
	})

	// Even an existing connection (e.g. from s2) should fail.
	assert.Equal(t, ErrChannelClosed, call(s2, s1), "closed channel should not accept incoming calls")

	require.NoError(t, call(s1, s2),
		"closed channel with pending incoming calls should allow outgoing calls")

	// Once the incoming connection is drained, outgoing calls should fail.
	s1C <- struct{}{}
	<-call2
	assert.Equal(t, ChannelInboundClosed, s1.State())
	require.Error(t, call(s1, s2),
		"closed channel with no pending incoming calls should not allow outgoing calls")

	// Now the channel should be completely closed as there are no pending connections.
	s2C <- struct{}{}
	<-call1
	assert.Equal(t, ChannelClosed, s1.State())

	// Close s2 so we don't leave any goroutines running.
	s2.Close()
	VerifyNoBlockedGoroutines(t)
}

func TestCloseSingleChannel(t *testing.T) {
	ctx, cancel := NewContext(time.Second)
	defer cancel()

	ch, err := testutils.NewServer(nil)
	require.NoError(t, err, "NewServer failed")

	var connected sync.WaitGroup
	var completed sync.WaitGroup
	blockCall := make(chan struct{})

	registerFunc(t, ch, "echo", func(ctx context.Context, args *raw.Args) (*raw.Res, error) {
		connected.Done()
		<-blockCall
		return &raw.Res{
			Arg2: args.Arg2,
			Arg3: args.Arg3,
		}, nil
	})

	for i := 0; i < 10; i++ {
		connected.Add(1)
		completed.Add(1)
		go func() {
			peerInfo := ch.PeerInfo()
			_, _, _, err := raw.Call(ctx, ch, peerInfo.HostPort, peerInfo.ServiceName, "echo", nil, nil)
			assert.NoError(t, err, "Call failed")
			completed.Done()
		}()
	}

	// Wait for all calls to connect before triggerring the Close (so they do not fail).
	connected.Wait()
	ch.Close()

	// Unblock the calls, and wait for all the calls to complete.
	close(blockCall)
	completed.Wait()

	// Once all calls are complete, the channel should be closed.
	runtime.Gosched()
	assert.Equal(t, ChannelClosed, ch.State())
	VerifyNoBlockedGoroutines(t)
}

func TestCloseOneSide(t *testing.T) {
	ctx, cancel := NewContext(time.Second)
	defer cancel()

	ch1, err := testutils.NewServer(&testutils.ChannelOpts{ServiceName: "client"})
	ch2, err := testutils.NewServer(&testutils.ChannelOpts{ServiceName: "server"})
	require.NoError(t, err, "NewServer 1 failed")
	require.NoError(t, err, "NewServer 2 failed")

	connected := make(chan struct{})
	completed := make(chan struct{})
	blockCall := make(chan struct{})
	registerFunc(t, ch2, "echo", func(ctx context.Context, args *raw.Args) (*raw.Res, error) {
		connected <- struct{}{}
		<-blockCall
		return &raw.Res{
			Arg2: args.Arg2,
			Arg3: args.Arg3,
		}, nil
	})

	go func() {
		ch2Peer := ch2.PeerInfo()
		_, _, _, err := raw.Call(ctx, ch1, ch2Peer.HostPort, ch2Peer.ServiceName, "echo", nil, nil)
		assert.NoError(t, err, "Call failed")
		completed <- struct{}{}
	}()

	// Wait for connected before calling Close.
	<-connected
	ch1.Close()

	// Now unblock the call and wait for the call to complete.
	close(blockCall)
	<-completed

	// Once the call completes, the channel should be closed.
	runtime.Gosched()
	assert.Equal(t, ChannelClosed, ch1.State())

	// We need to close all open TChannels before verifying blocked goroutines.
	ch2.Close()
	VerifyNoBlockedGoroutines(t)
}
<|endoftext|>


<commit_before>// Copyright © 2016 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

package cmd

import (
	"github.com/TheThingsNetwork/ttn/core"
	"github.com/TheThingsNetwork/ttn/core/adapters/http"
	"github.com/TheThingsNetwork/ttn/core/adapters/http/parser"
	"github.com/TheThingsNetwork/ttn/core/adapters/http/pubsub"
	"github.com/TheThingsNetwork/ttn/core/adapters/http/statuspage"
	"github.com/TheThingsNetwork/ttn/core/components"
	"github.com/apex/log"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

// brokerCmd represents the router command
var brokerCmd = &cobra.Command{
	Use:   "broker",
	Short: "The Things Network broker",
	Long: `
The broker is responsible for finding the right handler for uplink packets it
receives from routers. This means that handlers have to register applications
and personalized devices (with their network session keys) with the router.
	`,
	PreRun: func(cmd *cobra.Command, args []string) {
		ctx.WithFields(log.Fields{
			"database":      viper.GetString("broker.database"),
			"routers-port":  viper.GetInt("broker.routers-port"),
			"handlers-port": viper.GetInt("broker.handlers-port"),
		}).Info("Using Configuration")
	},
	Run: func(cmd *cobra.Command, args []string) {
		ctx.Info("Starting")

		// Instantiate all components
		rtrAdapter, err := http.NewAdapter(uint(viper.GetInt("broker.routers-port")), parser.JSON{}, ctx.WithField("adapter", "router-http"))
		if err != nil {
			ctx.WithError(err).Fatal("Could not start Routers Adapter")
		}

		hdlHTTPAdapter, err := http.NewAdapter(uint(viper.GetInt("broker.handlers-port")), parser.JSON{}, ctx.WithField("adapter", "handler-http"))
		if err != nil {
			ctx.WithError(err).Fatal("Could not start Handlers Adapter")
		}

		_, err = statuspage.NewAdapter(hdlHTTPAdapter, ctx.WithField("adapter", "statuspage-http"))
		if err != nil {
			ctx.WithError(err).Fatal("Could not start Broker Adapter")
		}

		hdlAdapter, err := pubsub.NewAdapter(hdlHTTPAdapter, parser.PubSub{}, ctx.WithField("adapter", "handler-pubsub"))
		if err != nil {
			ctx.WithError(err).Fatal("Could not start Handlers Adapter")
		}

		db, err := components.NewBrokerStorage()
		if err != nil {
			ctx.WithError(err).Fatal("Could not create a local storage")
		}

		broker := components.NewBroker(db, ctx)

		// Bring the service to life

		// Listen to uplink
		go func() {
			for {
				packet, an, err := rtrAdapter.Next()
				if err != nil {
					ctx.WithError(err).Error("Could not retrieve uplink")
					continue
				}
				go func(packet core.Packet, an core.AckNacker) {
					if err := broker.HandleUp(packet, an, hdlAdapter); err != nil {
						ctx.WithError(err).Error("Could not process uplink")
					}
				}(packet, an)
			}
		}()

		// List to handler registrations
		go func() {
			for {
				reg, an, err := hdlAdapter.NextRegistration()
				if err != nil {
					ctx.WithError(err).Error("Could not retrieve registration")
					continue
				}
				go func(reg core.Registration, an core.AckNacker) {
					if err := broker.Register(reg, an); err != nil {
						ctx.WithError(err).Error("Could not process registration")
					}
				}(reg, an)
			}
		}()

		<-make(chan bool)
	},
}

func init() {
	RootCmd.AddCommand(brokerCmd)

	brokerCmd.Flags().String("database", "boltdb:/tmp/ttn_broker.db", "Database connection")
	brokerCmd.Flags().Int("routers-port", 1690, "TCP port for connections from routers")
	brokerCmd.Flags().Int("handlers-port", 1790, "TCP port for connections from handlers")

	viper.BindPFlag("broker.database", brokerCmd.Flags().Lookup("database"))
	viper.BindPFlag("broker.routers-port", brokerCmd.Flags().Lookup("routers-port"))
	viper.BindPFlag("broker.handlers-port", brokerCmd.Flags().Lookup("handlers-port"))
}
<commit_msg>[refactor] Integrate API changes to broker command<commit_after>// Copyright © 2016 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

package cmd

import (
	"github.com/TheThingsNetwork/ttn/core"
	"github.com/TheThingsNetwork/ttn/core/adapters/http"
	"github.com/TheThingsNetwork/ttn/core/adapters/http/handlers"
	"github.com/TheThingsNetwork/ttn/core/components/broker"
	"github.com/apex/log"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

// brokerCmd represents the router command
var brokerCmd = &cobra.Command{
	Use:   "broker",
	Short: "The Things Network broker",
	Long: `
The broker is responsible for finding the right handler for uplink packets it
receives from routers. This means that handlers have to register applications
and personalized devices (with their network session keys) with the router.
	`,
	PreRun: func(cmd *cobra.Command, args []string) {
		ctx.WithFields(log.Fields{
			"database":      viper.GetString("broker.database"),
			"routers-port":  viper.GetInt("broker.routers-port"),
			"handlers-port": viper.GetInt("broker.handlers-port"),
		}).Info("Using Configuration")
	},
	Run: func(cmd *cobra.Command, args []string) {
		ctx.Info("Starting")

		// Instantiate all components
		rtrAdapter, err := http.NewAdapter(uint(viper.GetInt("broker.routers-port")), nil, ctx.WithField("adapter", "router-http"))
		if err != nil {
			ctx.WithError(err).Fatal("Could not start Routers Adapter")
		}
		rtrAdapter.Bind(handlers.Collect{})

		hdlAdapter, err := http.NewAdapter(uint(viper.GetInt("broker.handlers-port")), nil, ctx.WithField("adapter", "handler-http"))
		if err != nil {
			ctx.WithError(err).Fatal("Could not start Handlers Adapter")
		}
		hdlAdapter.Bind(handlers.Collect{})
		hdlAdapter.Bind(handlers.PubSub{})
		hdlAdapter.Bind(handlers.StatusPage{})

		db, err := broker.NewStorage("broker_storage.db") // TODO Use a cli flag
		if err != nil {
			ctx.WithError(err).Fatal("Could not create a local storage")
		}

		broker := broker.New(db, ctx)

		// Bring the service to life

		// Listen to uplink
		go func() {
			for {
				packet, an, err := rtrAdapter.Next()
				if err != nil {
					ctx.WithError(err).Error("Could not retrieve uplink")
					continue
				}
				go func(packet []byte, an core.AckNacker) {
					if err := broker.HandleUp(packet, an, hdlAdapter); err != nil {
						ctx.WithError(err).Error("Could not process uplink")
					}
				}(packet, an)
			}
		}()

		// List to handler registrations
		go func() {
			for {
				reg, an, err := hdlAdapter.NextRegistration()
				if err != nil {
					ctx.WithError(err).Error("Could not retrieve registration")
					continue
				}
				go func(reg core.Registration, an core.AckNacker) {
					if err := broker.Register(reg, an); err != nil {
						ctx.WithError(err).Error("Could not process registration")
					}
				}(reg, an)
			}
		}()

		<-make(chan bool)
	},
}

func init() {
	RootCmd.AddCommand(brokerCmd)

	brokerCmd.Flags().String("database", "boltdb:/tmp/ttn_broker.db", "Database connection")
	brokerCmd.Flags().Int("routers-port", 1690, "TCP port for connections from routers")
	brokerCmd.Flags().Int("handlers-port", 1790, "TCP port for connections from handlers")

	viper.BindPFlag("broker.database", brokerCmd.Flags().Lookup("database"))
	viper.BindPFlag("broker.routers-port", brokerCmd.Flags().Lookup("routers-port"))
	viper.BindPFlag("broker.handlers-port", brokerCmd.Flags().Lookup("handlers-port"))
}
<|endoftext|>


<commit_before>// Copyright 2014 Volker Dobler.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"flag"
	"log"
	"os"

	"github.com/vdobler/ht/ht"
)

var cmdRun = &Command{
	RunTests:    runRun,
	Usage:       "run <test>...",
	Description: "run a single test",
	Flag:        flag.NewFlagSet("run", flag.ContinueOnError),
	Help: `
Run loads the single test, unrolls it and prepares it and executes the
test (or the first of the unrolled tests each).
Variables set with the -D flag overwrite variables read from file with -Dfile.
	`,
}

func init() {
	addOutputFlag(cmdRun.Flag)

	addTestFlags(cmdRun.Flag)
}

func runRun(cmd *Command, tests []*ht.Test) {
	logger := log.New(os.Stdout, "", log.LstdFlags)
	suite := &ht.Suite{
		Name:      "Autogenerated suite for " + cmd.Name(),
		Log:       logger,
		Variables: variablesFlag,
	}

	suite.Tests = tests
	err := suite.Prepare()
	if err != nil {
		log.Println(err.Error())
		os.Exit(3)
	}
	if verbosity != -99 {
		for i := range suite.Tests {
			suite.Tests[i].Verbosity = verbosity
		}
	}
	suite.Variables = variablesFlag
	runExecute(cmd, []*ht.Suite{suite})
}
<commit_msg>cmd/ht: use a cookiejar even when 'run'ing a single test<commit_after>// Copyright 2014 Volker Dobler.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"flag"
	"log"
	"os"

	"github.com/vdobler/ht/ht"
)

var cmdRun = &Command{
	RunTests:    runRun,
	Usage:       "run <test>...",
	Description: "run a single test",
	Flag:        flag.NewFlagSet("run", flag.ContinueOnError),
	Help: `
Run loads the single test, unrolls it and prepares it and executes the
test (or the first of the unrolled tests each).
Variables set with the -D flag overwrite variables read from file with -Dfile.
	`,
}

func init() {
	addOutputFlag(cmdRun.Flag)

	addTestFlags(cmdRun.Flag)
}

func runRun(cmd *Command, tests []*ht.Test) {
	logger := log.New(os.Stdout, "", log.LstdFlags)
	suite := &ht.Suite{
		Name:        "Autogenerated suite for " + cmd.Name(),
		Log:         logger,
		Variables:   variablesFlag,
		KeepCookies: true,
	}

	suite.Tests = tests
	err := suite.Prepare()
	if err != nil {
		log.Println(err.Error())
		os.Exit(3)
	}
	if verbosity != -99 {
		for i := range suite.Tests {
			suite.Tests[i].Verbosity = verbosity
		}
	}
	suite.Variables = variablesFlag
	runExecute(cmd, []*ht.Suite{suite})
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"

	"github.com/fatih/color"
)

// StatusLinePrinter provides printing facilities for dynamically updating
// status lines in the console. It supports colorized printing.
type StatusLinePrinter struct {
	// nonEmpty indicates whether or not the printer has printed any non-empty
	// content to the status line.
	nonEmpty bool
}

// Print prints a message to the status line, overwriting any existing content.
// Color escape sequences are supported. Messages will be truncated to a
// platform-dependent maximum length and padded appropriately.
func (p *StatusLinePrinter) Print(message string) {
	// Print the message, prefixed with a carriage return to wipe out the
	// previous line (if any). Ensure that the status prints as a specified
	// width, truncating or right-padding with space as necessary. On POSIX
	// systems, this width is 80 characters and on Windows it's 79. The reason
	// for 79 on Windows is that for cmd.exe consoles the line width needs to be
	// narrower than the console (which is 80 columns by default) for carriage
	// return wipes to work (if it's the same width, the next carriage return
	// overflows to the next line, behaving exactly like a newline). We print to
	// the color output so that color escape sequences are properly handled - in
	// all other cases this will behave just like standard output.
	// TODO: We should probably try to detect the console width.
	fmt.Fprintf(color.Output, statusLineFormat, message)

	// Update our non-empty status. We're always non-empty after printing
	// because we print padding as well.
	p.nonEmpty = true
}

// Clear clears any content on the status line and moves the cursor back to the
// beginning of the line.
func (p *StatusLinePrinter) Clear() {
	// Write over any existing data.
	p.Print("")

	// Wipe out any existing line.
	fmt.Print("\r")

	// Update our non-empty status.
	p.nonEmpty = false
}

// BreakIfNonEmpty prints a newline character if the current line is non-empty.
func (p *StatusLinePrinter) BreakIfNonEmpty() {
	// If the status line contents are non-empty, then print a newline and mark
	// ourselves as empty.
	if p.nonEmpty {
		fmt.Println()
		p.nonEmpty = false
	}
}
<commit_msg>Modified StatusLinePrinter to support standard error.<commit_after>package cmd

import (
	"fmt"
	"os"

	"github.com/fatih/color"
)

// StatusLinePrinter provides printing facilities for dynamically updating
// status lines in the console. It supports colorized printing.
type StatusLinePrinter struct {
	// UseStandardError causes the printer to use standard error for its output
	// instead of standard output (the default).
	UseStandardError bool
	// nonEmpty indicates whether or not the printer has printed any non-empty
	// content to the status line.
	nonEmpty bool
}

// Print prints a message to the status line, overwriting any existing content.
// Color escape sequences are supported. Messages will be truncated to a
// platform-dependent maximum length and padded appropriately.
func (p *StatusLinePrinter) Print(message string) {
	// Determine output stream.
	output := color.Output
	if p.UseStandardError {
		output = color.Error
	}

	// Print the message, prefixed with a carriage return to wipe out the
	// previous line (if any). Ensure that the status prints as a specified
	// width, truncating or right-padding with space as necessary. On POSIX
	// systems, this width is 80 characters and on Windows it's 79. The reason
	// for 79 on Windows is that for cmd.exe consoles the line width needs to be
	// narrower than the console (which is 80 columns by default) for carriage
	// return wipes to work (if it's the same width, the next carriage return
	// overflows to the next line, behaving exactly like a newline). We print to
	// the color output so that color escape sequences are properly handled - in
	// all other cases this will behave just like standard output.
	// TODO: We should probably try to detect the console width.
	fmt.Fprintf(output, statusLineFormat, message)

	// Update our non-empty status. We're always non-empty after printing
	// because we print padding as well.
	p.nonEmpty = true
}

// Clear clears any content on the status line and moves the cursor back to the
// beginning of the line.
func (p *StatusLinePrinter) Clear() {
	// Write over any existing data.
	p.Print("")

	// Determine output stream.
	output := os.Stdout
	if p.UseStandardError {
		output = os.Stderr
	}

	// Wipe out any existing line.
	fmt.Fprint(output, "\r")

	// Update our non-empty status.
	p.nonEmpty = false
}

// BreakIfNonEmpty prints a newline character if the current line is non-empty.
func (p *StatusLinePrinter) BreakIfNonEmpty() {
	// If the status line contents are non-empty, then print a newline and mark
	// ourselves as empty.
	if p.nonEmpty {
		// Determine output stream.
		output := os.Stdout
		if p.UseStandardError {
			output = os.Stderr
		}

		// Print a line break.
		fmt.Fprintln(output)

		// Update our non-empty status.
		p.nonEmpty = false
	}
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"io/ioutil"
	"log"
	"path/filepath"

	"github.com/codegangsta/cli"
	"github.com/exercism/cli/api"
	"github.com/exercism/cli/config"
)

// Submit posts an iteration to the api
func Submit(ctx *cli.Context) {
	if len(ctx.Args()) == 0 {
		log.Fatal("Please enter a file name")
	}

	c, err := config.Read(ctx.GlobalString("config"))
	if err != nil {
		log.Fatal(err)
	}

	if !c.IsAuthenticated() {
		log.Fatal(msgPleaseAuthenticate)
	}

	filename := ctx.Args()[0]

	if isTest(filename) {
		log.Fatal("Please submit the solution, not the test file.")
	}

	file, err := filepath.Abs(filename)
	if err != nil {
		log.Fatal(err)
	}
	file, err = filepath.EvalSymlinks(file)
	if err != nil {
		log.Fatal(err)
	}

	dir, err := filepath.EvalSymlinks(c.Dir)
	if err != nil {
		log.Fatal(err)
	}

	code, err := ioutil.ReadFile(file)
	if err != nil {
		log.Fatalf("Cannot read the contents of %s - %s\n", filename, err)
	}

	url := fmt.Sprintf("%s/api/v1/user/assignments", c.API)

	iteration := &api.Iteration{
		Key:  c.APIKey,
		Code: string(code),
		File: file,
		Dir:  dir,
	}

	if err = iteration.Identify(); err != nil {
		msg := `Please leave the solution within the problem directory that was created by 'exercism fetch'`
		log.Fatalf("Cannot submit - %s.\n\n%s", err, msg)
	}

	submission, err := api.Submit(url, iteration)
	if err != nil {
		log.Fatal(err)
	}

	msg := "Submitted %s in %s. Your submission can be found online at %s\n"
	fmt.Printf(msg, submission.Name, submission.Language, submission.URL)
}
<commit_msg>Add info about fetching next problem. Closes #126<commit_after>package cmd

import (
	"fmt"
	"io/ioutil"
	"log"
	"path/filepath"

	"github.com/codegangsta/cli"
	"github.com/exercism/cli/api"
	"github.com/exercism/cli/config"
)

// Submit posts an iteration to the api
func Submit(ctx *cli.Context) {
	if len(ctx.Args()) == 0 {
		log.Fatal("Please enter a file name")
	}

	c, err := config.Read(ctx.GlobalString("config"))
	if err != nil {
		log.Fatal(err)
	}

	if !c.IsAuthenticated() {
		log.Fatal(msgPleaseAuthenticate)
	}

	filename := ctx.Args()[0]

	if isTest(filename) {
		log.Fatal("Please submit the solution, not the test file.")
	}

	file, err := filepath.Abs(filename)
	if err != nil {
		log.Fatal(err)
	}
	file, err = filepath.EvalSymlinks(file)
	if err != nil {
		log.Fatal(err)
	}

	dir, err := filepath.EvalSymlinks(c.Dir)
	if err != nil {
		log.Fatal(err)
	}

	code, err := ioutil.ReadFile(file)
	if err != nil {
		log.Fatalf("Cannot read the contents of %s - %s\n", filename, err)
	}

	url := fmt.Sprintf("%s/api/v1/user/assignments", c.API)

	iteration := &api.Iteration{
		Key:  c.APIKey,
		Code: string(code),
		File: file,
		Dir:  dir,
	}

	if err = iteration.Identify(); err != nil {
		msg := `Please leave the solution within the problem directory that was created by 'exercism fetch'`
		log.Fatalf("Cannot submit - %s.\n\n%s", err, msg)
	}

	submission, err := api.Submit(url, iteration)
	if err != nil {
		log.Fatal(err)
	}

	msg := `
Submitted %s in %s.
Your submission can be found online at %s

To get the next exercise, run "exercism fetch" again.
`
	fmt.Printf(msg, submission.Name, submission.Language, submission.URL)
}
<|endoftext|>


<commit_before>//
// Copyright © 2011-2018 Guy M. Allard
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

package stompngo

import (
	"log"
	"os"
	"testing"
	"time"
)

var _ = log.Println

// Test STOMP 1.1 Header Codec - Basic Encode.
func TestCodecEncodeBasic(t *testing.T) {
	for _, _ = range Protocols() {
		for _, ede := range tdList {
			ev := encode(ede.decoded)
			if ede.encoded != ev {
				t.Fatalf("TestCodecEncodeBasic ENCODE ERROR: expected: [%v] got: [%v]",
					ede.encoded, ev)
			}
		}
	}
}

/*
	Test STOMP 1.1 Header Codec - Basic Decode.
*/
func TestCodecDecodeBasic(t *testing.T) {
	for _, _ = range Protocols() {
		for _, ede := range tdList {
			dv := decode(ede.encoded)
			if ede.decoded != dv {
				t.Fatalf("TestCodecDecodeBasic DECODE ERROR: expected: [%v] got: [%v]",
					ede.decoded, dv)
			}
		}
	}
}

func BenchmarkCodecEncode(b *testing.B) {
	for _, _ = range Protocols() {
		for i := 0; i < len(tdList); i++ {
			for n := 0; n < b.N; n++ {
				_ = encode(tdList[i].decoded)
			}
		}
	}
}

func BenchmarkCodecDecode(b *testing.B) {
	for _, _ = range Protocols() {
		for i := 0; i < len(tdList); i++ {
			for n := 0; n < b.N; n++ {
				_ = decode(tdList[i].encoded)
			}
		}
	}
}

/*
	Test STOMP 1.1 Send / Receive - no codec error.
*/
func TestCodecSendRecvCodec(t *testing.T) {
	//
	for _, p := range Protocols() {
		usemap := srcdmap[p]
		//log.Printf("Protocol: %s\n", p)
		//log.Printf("MapLen: %d\n", len(usemap))
		for _, v := range usemap {

			//
			// RMQ and STOMP Level 1.0 :
			// Headers are encoded (as if the STOMP protocol were 1.1
			// or 1.2).
			// MAYBEDO: Report issue.  (Is this a bug or a feature?)
			//
			if p == SPL_10 && os.Getenv("STOMP_RMQ") != "" {
				continue
			}

			n, _ = openConn(t)
			ch := login_headers
			ch = headersProtocol(ch, p)
			conn, e = Connect(n, ch)
			if e != nil {
				t.Fatalf("TestCodecSendRecvCodec CONNECT expected nil, got %v\n", e)
			}
			//
			d := tdest("/queue/gostomp.codec.sendrecv.1.protocol." + p)
			ms := "msg.codec.sendrecv.1.protocol." + p + " - a message"
			wh := Headers{HK_DESTINATION, d}

			//log.Printf("TestData: %+v\n", v)
			sh := wh.Clone()
			for i := range v.sk {
				sh = sh.Add(v.sk[i], v.sv[i])
			}
			// Send
			//log.Printf("Send Headers: %v\n", sh)
			e = conn.Send(sh, ms)
			if e != nil {
				t.Fatalf("TestCodecSendRecvCodec Send failed: %v protocol:%s\n",
					e, p)
			}
			// Check for ERROR frame
			time.Sleep(1e9 / 8) // Wait one eigth
			// Poll for adhoc ERROR from server
			select {
			case vx := <-conn.MessageData:
				t.Fatalf("TestCodecSendRecvCodec Send Error: [%v] protocol:%s\n",
					vx, p)
			default:
				//
			}
			// Subscribe
			sbh := wh.Add(HK_ID, v.sid)
			//log.Printf("Subscribe Headers: %v\n", sbh)
			sc, e = conn.Subscribe(sbh)
			if e != nil {
				t.Fatalf("TestCodecSendRecvCodec Subscribe failed: %v protocol:%s\n",
					e, p)
			}
			if sc == nil {
				t.Fatalf("TestCodecSendRecvCodec Subscribe sub chan is nil protocol:%s\n",
					p)
			}
			//
			checkReceivedMD(t, conn, sc, "codec_test_"+p) // Receive
			// Check body data
			b := md.Message.BodyString()
			if b != ms {
				t.Fatalf("TestCodecSendRecvCodec Receive expected: [%v] got: [%v] protocol:%s\n",
					ms, b, p)
			}
			// Unsubscribe
			//log.Printf("Unsubscribe Headers: %v\n", sbh)
			e = conn.Unsubscribe(sbh)
			if e != nil {
				t.Fatalf("TestCodecSendRecvCodec Unsubscribe failed: %v protocol:%s\n",
					e, p)
			}
			// Check headers
			//log.Printf("Receive Headers: %v\n", md.Message.Headers)
			for key, value := range v.rv {
				hv, ok = md.Message.Headers.Contains(key)
				if !ok {
					t.Fatalf("TestCodecSendRecvCodec Header key expected: [%v] got: [%v] protocol:%s\n",
						key, ok, p)
				}
				if value != hv {
					t.Fatalf("TestCodecSendRecvCodec Header value expected: [%v] got: [%v] protocol:%s\n",
						value, hv, p)
				}
			}
			//
			checkReceived(t, conn, false)
			e = conn.Disconnect(empty_headers)
			checkDisconnectError(t, e)
			_ = closeConn(t, n)
		}
		//
	}
}
<commit_msg>More logging in codec test.<commit_after>//
// Copyright © 2011-2018 Guy M. Allard
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

package stompngo

import (
	"log"
	"os"
	"testing"
	"time"
)

var _ = log.Println

// Test STOMP 1.1 Header Codec - Basic Encode.
func TestCodecEncodeBasic(t *testing.T) {
	for _, _ = range Protocols() {
		for _, ede := range tdList {
			ev := encode(ede.decoded)
			if ede.encoded != ev {
				t.Fatalf("TestCodecEncodeBasic ENCODE ERROR: expected: [%v] got: [%v]",
					ede.encoded, ev)
			}
		}
	}
}

/*
	Test STOMP 1.1 Header Codec - Basic Decode.
*/
func TestCodecDecodeBasic(t *testing.T) {
	for _, _ = range Protocols() {
		for _, ede := range tdList {
			dv := decode(ede.encoded)
			if ede.decoded != dv {
				t.Fatalf("TestCodecDecodeBasic DECODE ERROR: expected: [%v] got: [%v]",
					ede.decoded, dv)
			}
		}
	}
}

func BenchmarkCodecEncode(b *testing.B) {
	for _, _ = range Protocols() {
		for i := 0; i < len(tdList); i++ {
			for n := 0; n < b.N; n++ {
				_ = encode(tdList[i].decoded)
			}
		}
	}
}

func BenchmarkCodecDecode(b *testing.B) {
	for _, _ = range Protocols() {
		for i := 0; i < len(tdList); i++ {
			for n := 0; n < b.N; n++ {
				_ = decode(tdList[i].encoded)
			}
		}
	}
}

/*
	Test STOMP 1.1 Send / Receive - no codec error.
*/
func TestCodecSendRecvCodec(t *testing.T) {
	//
	for _, p := range Protocols() {
		usemap := srcdmap[p]
		//log.Printf("Protocol: %s\n", p)
		//log.Printf("MapLen: %d\n", len(usemap))
		for _, v := range usemap {

			//
			// RMQ and STOMP Level 1.0 :
			// Headers are encoded (as if the STOMP protocol were 1.1
			// or 1.2).
			// MAYBEDO: Report issue.  (Is this a bug or a feature?)
			//
			if p == SPL_10 && os.Getenv("STOMP_RMQ") != "" {
				continue
			}

			n, _ = openConn(t)
			ch := login_headers
			ch = headersProtocol(ch, p)
			conn, e = Connect(n, ch)
			if e != nil {
				t.Fatalf("TestCodecSendRecvCodec CONNECT expected nil, got %v\n", e)
			}
			//
			d := tdest("/queue/gostomp.codec.sendrecv.1.protocol." + p)
			ms := "msg.codec.sendrecv.1.protocol." + p + " - a message"
			wh := Headers{HK_DESTINATION, d}

			//log.Printf("TestData: %+v\n", v)
			sh := wh.Clone()
			for i := range v.sk {
				sh = sh.Add(v.sk[i], v.sv[i])
			}
			// Send
			//log.Printf("Send Headers: %v\n", sh)
			e = conn.Send(sh, ms)
			if e != nil {
				t.Fatalf("TestCodecSendRecvCodec Send failed: %v protocol:%s\n",
					e, p)
			}
			// Check for ERROR frame
			time.Sleep(1e9 / 8) // Wait one eigth
			// Poll for adhoc ERROR from server
			select {
			case vx := <-conn.MessageData:
				t.Fatalf("TestCodecSendRecvCodec Send Error: [%v] protocol:%s\n",
					vx, p)
			default:
				//
			}
			// Subscribe
			sbh := wh.Add(HK_ID, v.sid)
			//log.Printf("Subscribe Headers: %v\n", sbh)
			sc, e = conn.Subscribe(sbh)
			if e != nil {
				t.Fatalf("TestCodecSendRecvCodec Subscribe failed: %v protocol:%s\n",
					e, p)
			}
			if sc == nil {
				t.Fatalf("TestCodecSendRecvCodec Subscribe sub chan is nil protocol:%s\n",
					p)
			}
			//
			checkReceivedMD(t, conn, sc, "codec_test_"+p) // Receive
			// Check body data
			b := md.Message.BodyString()
			if b != ms {
				t.Fatalf("TestCodecSendRecvCodec Receive expected: [%v] got: [%v] protocol:%s\n",
					ms, b, p)
			}
			// Unsubscribe
			//log.Printf("Unsubscribe Headers: %v\n", sbh)
			e = conn.Unsubscribe(sbh)
			if e != nil {
				t.Fatalf("TestCodecSendRecvCodec Unsubscribe failed: %v protocol:%s\n",
					e, p)
			}
			// Check headers
			log.Printf("Receive Headers: %v\n", md.Message.Headers)
			log.Printf("Check map: %v\n", v.rv)
			for key, value := range v.rv {
				log.Printf("Want Key: [%v] Value: [%v] \n", key, value)
				hv, ok = md.Message.Headers.Contains(key)
				if !ok {
					t.Fatalf("TestCodecSendRecvCodec Header key expected: [%v] got: [%v] protocol:%s\n",
						key, hv, p)
				}
				if value != hv {
					t.Fatalf("TestCodecSendRecvCodec Header value expected: [%v] got: [%v] protocol:%s\n",
						value, hv, p)
				}
			}
			//
			checkReceived(t, conn, false)
			e = conn.Disconnect(empty_headers)
			checkDisconnectError(t, e)
			_ = closeConn(t, n)
		}
		//
	}
}
<|endoftext|>


<commit_before>// SPDX-License-Identifier: MIT

package colors

import (
	"fmt"
	"io"
	"os"

	"github.com/issue9/term/v2/ansi"
)

// Fprint 带色彩输出的 fmt.Fprint
//
// 颜色值只在 w 不为 os.Stderr、os.Stdin、os.Stdout 中的一个时才启作用，否则只向 w 输出普通字符串。
func Fprint(w io.Writer, t Type, foreground, background Color, v ...interface{}) (int, error) {
	return fmt.Fprint(w, sprint(!isConsole(w), t, foreground, background, v...))
}

// Fprintln 带色彩输出的 fmt.Fprintln
//
// 颜色值只在 w 不为 os.Stderr、os.Stdin、os.Stdout 中的一个时才启作用，否则只向 w 输出普通字符串。
func Fprintln(w io.Writer, t Type, foreground, background Color, v ...interface{}) (int, error) {
	return fmt.Fprintln(w, sprint(!isConsole(w), t, foreground, background, v...))
}

// Fprintf 带色彩输出的 fmt.Fprintf
//
// 颜色值只在 w 不为 os.Stderr、os.Stdin、os.Stdout 中的一个时才启作用，否则只向 w 输出普通字符串。
func Fprintf(w io.Writer, t Type, foreground, background Color, format string, v ...interface{}) (int, error) {
	if !isConsole(w) {
		return fmt.Fprintf(w, format, v...)
	}

	if !isValidType(t) {
		panic("无效的参数 t")
	}

	if t == Normal {
		return fmt.Fprint(w, string(foreground.FColor())+string(background.BColor())+
			fmt.Sprint(v...)+
			string(ansi.CSI('m', ansi.ResetCode)))
	}

	return fmt.Fprint(w, string(ansi.CSI('m', int(t))+foreground.FColor())+string(background.BColor())+
		fmt.Sprintf(format, v...)+
		string(ansi.CSI('m', ansi.ResetCode)))
}

// Print 带色彩输出的 fmt.Print
func Print(t Type, foreground, background Color, v ...interface{}) (int, error) {
	return Fprint(os.Stdout, t, foreground, background, v...)
}

// Println 带色彩输出的 fmt.Println
func Println(t Type, foreground, background Color, v ...interface{}) (int, error) {
	return Fprintln(os.Stdout, t, foreground, background, v...)
}

// Printf 带色彩输出的 fmt.Printf
func Printf(t Type, foreground, background Color, format string, v ...interface{}) (int, error) {
	return Fprintf(os.Stdout, t, foreground, background, format, v...)
}

func sprint(ignoreAnsi bool, t Type, foreground, background Color, v ...interface{}) string {
	if ignoreAnsi {
		return fmt.Sprint(v...)
	}

	if !isValidType(t) {
		panic("无效的参数 t")
	}

	if t == Normal {
		return string(foreground.FColor()) + string(background.BColor()) +
			fmt.Sprint(v...) +
			string(ansi.CSI('m', ansi.ResetCode))
	}

	return string(ansi.CSI('m', int(t))+foreground.FColor()) + string(background.BColor()) +
		fmt.Sprint(v...) +
		string(ansi.CSI('m', ansi.ResetCode))
}

// 判断 w 是否为 stderr、stdout、stdin 三者之一
func isConsole(w io.Writer) bool {
	return w == os.Stderr || w == os.Stdout || w == os.Stdin
}
<commit_msg>fix(colors): 修正 Fprintf 在 t == Normal 时无法输出内容的错误<commit_after>// SPDX-License-Identifier: MIT

package colors

import (
	"fmt"
	"io"
	"os"

	"github.com/issue9/term/v2/ansi"
)

// Fprint 带色彩输出的 fmt.Fprint
//
// 颜色值只在 w 不为 os.Stderr、os.Stdin、os.Stdout 中的一个时才启作用，否则只向 w 输出普通字符串。
func Fprint(w io.Writer, t Type, foreground, background Color, v ...interface{}) (int, error) {
	return fmt.Fprint(w, sprint(!isConsole(w), t, foreground, background, v...))
}

// Fprintln 带色彩输出的 fmt.Fprintln
//
// 颜色值只在 w 不为 os.Stderr、os.Stdin、os.Stdout 中的一个时才启作用，否则只向 w 输出普通字符串。
func Fprintln(w io.Writer, t Type, foreground, background Color, v ...interface{}) (int, error) {
	return fmt.Fprintln(w, sprint(!isConsole(w), t, foreground, background, v...))
}

// Fprintf 带色彩输出的 fmt.Fprintf
//
// 颜色值只在 w 不为 os.Stderr、os.Stdin、os.Stdout 中的一个时才启作用，否则只向 w 输出普通字符串。
func Fprintf(w io.Writer, t Type, foreground, background Color, format string, v ...interface{}) (int, error) {
	if !isConsole(w) {
		return fmt.Fprintf(w, format, v...)
	}

	if !isValidType(t) {
		panic("无效的参数 t")
	}

	if t == Normal {
		return fmt.Fprint(w, string(foreground.FColor())+string(background.BColor())+
			fmt.Sprintf(format, v...)+
			string(ansi.CSI('m', ansi.ResetCode)))
	}

	return fmt.Fprint(w, string(ansi.CSI('m', int(t))+foreground.FColor())+string(background.BColor())+
		fmt.Sprintf(format, v...)+
		string(ansi.CSI('m', ansi.ResetCode)))
}

// Print 带色彩输出的 fmt.Print
func Print(t Type, foreground, background Color, v ...interface{}) (int, error) {
	return Fprint(os.Stdout, t, foreground, background, v...)
}

// Println 带色彩输出的 fmt.Println
func Println(t Type, foreground, background Color, v ...interface{}) (int, error) {
	return Fprintln(os.Stdout, t, foreground, background, v...)
}

// Printf 带色彩输出的 fmt.Printf
func Printf(t Type, foreground, background Color, format string, v ...interface{}) (int, error) {
	return Fprintf(os.Stdout, t, foreground, background, format, v...)
}

func sprint(ignoreAnsi bool, t Type, foreground, background Color, v ...interface{}) string {
	if ignoreAnsi {
		return fmt.Sprint(v...)
	}

	if !isValidType(t) {
		panic("无效的参数 t")
	}

	if t == Normal {
		return string(foreground.FColor()) + string(background.BColor()) +
			fmt.Sprint(v...) +
			string(ansi.CSI('m', ansi.ResetCode))
	}

	return string(ansi.CSI('m', int(t))+foreground.FColor()) + string(background.BColor()) +
		fmt.Sprint(v...) +
		string(ansi.CSI('m', ansi.ResetCode))
}

// 判断 w 是否为 stderr、stdout、stdin 三者之一
func isConsole(w io.Writer) bool {
	return w == os.Stderr || w == os.Stdout || w == os.Stdin
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"log"
	"os"
	"strings"

	"github.com/brotherlogic/goserver"
	"golang.org/x/net/context"
	"google.golang.org/grpc"

	pb "github.com/brotherlogic/gobuildslave/proto"
)

// Server the main server type
type Server struct {
	*goserver.GoServer
	runner *Runner
}

// BuildJob builds out a job
func (s *Server) BuildJob(ctx context.Context, in *pb.JobSpec) (*pb.Empty, error) {
	s.runner.Checkout(in.Name)
	return &pb.Empty{}, nil
}

// Run runs a background task
func (s *Server) Run(ctx context.Context, in *pb.JobSpec) (*pb.Empty, error) {
	s.runner.Run(in.Name)
	return &pb.Empty{}, nil
}

// DoRegister Registers this server
func (s Server) DoRegister(server *grpc.Server) {
	pb.RegisterGoBuildSlaveServer(server, &s)
}

//Init builds the default runner framework
func Init() *Runner {
	r := &Runner{gopath: "goautobuild"}
	r.runner = runCommand
	go r.run()
	return r
}

func runCommand(c *runnerCommand) {
	log.Printf("RUNNING COMMAND: %v", c)
	env := os.Environ()
	home := ""
	for _, s := range env {
		if strings.HasPrefix(s, "HOME=") {
			home = s[5:]
		}
	}

	if len(home) == 0 {

	}

	path := fmt.Sprintf("GOPATH=" + home + "/gobuild")
	found := false
	log.Printf("HERE = %v", c.command.Env)
	envl := os.Environ()
	for i, blah := range envl {
		if strings.HasPrefix(blah, "GOPATH") {
			envl[i] = path
			found = true
		}
	}
	if !found {
		envl = append(envl, path)
	}
	log.Printf("ENV = %v", envl)
	c.command.Env = envl

	out, err := c.command.StdoutPipe()
	out2, err2 := c.command.StderrPipe()
	if err != nil {
		log.Printf("Blah: %v", err)
	}

	if err2 != nil {
		log.Printf("Blah2: %v", err)
	}

	log.Printf("%v, %v and %v", c.command.Path, c.command.Args, c.command.Env)
	c.command.Start()

	buf := new(bytes.Buffer)
	buf.ReadFrom(out)
	str := buf.String()

	buf2 := new(bytes.Buffer)
	buf2.ReadFrom(out2)
	str2 := buf2.String()
	log.Printf("%v and %v", str, str2)

	if !c.background {
		c.command.Wait()
		c.output = str
		c.complete = true
	}
}

func main() {
	s := Server{&goserver.GoServer{}, Init()}
	s.Register = s
	s.PrepServer()
	s.RegisterServer("gobuildslave", false)
	s.Serve()
}
<commit_msg>Fixed cat command<commit_after>package main

import (
	"bytes"
	"fmt"
	"log"
	"os"
	"strings"

	"github.com/brotherlogic/goserver"
	"golang.org/x/net/context"
	"google.golang.org/grpc"

	pb "github.com/brotherlogic/gobuildslave/proto"
)

// Server the main server type
type Server struct {
	*goserver.GoServer
	runner *Runner
}

// BuildJob builds out a job
func (s *Server) BuildJob(ctx context.Context, in *pb.JobSpec) (*pb.Empty, error) {
	s.runner.Checkout(in.Name)
	return &pb.Empty{}, nil
}

// Run runs a background task
func (s *Server) Run(ctx context.Context, in *pb.JobSpec) (*pb.Empty, error) {
	s.runner.Run(in.Name)
	return &pb.Empty{}, nil
}

// DoRegister Registers this server
func (s Server) DoRegister(server *grpc.Server) {
	pb.RegisterGoBuildSlaveServer(server, &s)
}

//Init builds the default runner framework
func Init() *Runner {
	r := &Runner{gopath: "goautobuild"}
	r.runner = runCommand
	go r.run()
	return r
}

func runCommand(c *runnerCommand) {
	log.Printf("RUNNING COMMAND: %v", c)
	env := os.Environ()
	home := ""
	for _, s := range env {
		if strings.HasPrefix(s, "HOME=") {
			home = s[5:]
		}
	}

	if len(home) == 0 {

	}
	gpath := home + "/gobuild"
	c.command.Path = strings.Replace(c.command.Path, "$GOPATH", gpath, -1)
	for i := range c.command.Args {
		c.command.Args[i] = strings.Replace(c.command.Args[i], "$GOPATH", gpath, -1)
	}

	path := fmt.Sprintf("GOPATH=" + home + "/gobuild")
	found := false
	log.Printf("HERE = %v", c.command.Env)
	envl := os.Environ()
	for i, blah := range envl {
		if strings.HasPrefix(blah, "GOPATH") {
			envl[i] = path
			found = true
		}
	}
	if !found {
		envl = append(envl, path)
	}
	log.Printf("ENV = %v", envl)
	c.command.Env = envl

	out, err := c.command.StdoutPipe()
	out2, err2 := c.command.StderrPipe()
	if err != nil {
		log.Printf("Blah: %v", err)
	}

	if err2 != nil {
		log.Printf("Blah2: %v", err)
	}

	log.Printf("%v, %v and %v", c.command.Path, c.command.Args, c.command.Env)
	c.command.Start()

	buf := new(bytes.Buffer)
	buf.ReadFrom(out)
	str := buf.String()

	buf2 := new(bytes.Buffer)
	buf2.ReadFrom(out2)
	str2 := buf2.String()
	log.Printf("%v and %v", str, str2)

	if !c.background {
		c.command.Wait()
		c.output = str
		c.complete = true
	}
}

func main() {
	s := Server{&goserver.GoServer{}, Init()}
	s.Register = s
	s.PrepServer()
	s.RegisterServer("gobuildslave", false)
	s.Serve()
}
<|endoftext|>