<commit_before>// go-rst - A reStructuredText parser for Go
// 2014 (c) The go-rst Authors
// MIT Licensed. See LICENSE for details.

package parse

import (
	"fmt"
	"github.com/demizer/go-elog"
	"reflect"
)

type systemMessageLevel int

const (
	levelInfo systemMessageLevel = iota
	levelWarning
	levelError
	levelSevere
)

var systemMessageLevels = [...]string{
	"INFO",
	"WARNING",
	"ERROR",
	"SEVERE",
}

func (s systemMessageLevel) String() string {
	return systemMessageLevels[s]
}

type systemMessage struct {
	level  systemMessageLevel
	line   int
	source string
	items  []item
}

type sectionLevels []*SectionNode

func (s *sectionLevels) String() string {
	var out string
	for lvl, sec := range *s {
		out += fmt.Sprintf("level: %d, rune: %q, overline: %t, length: %d\n",
			lvl+1, sec.char, sec.overline, sec.length)
	}
	return out
}

func (s *sectionLevels) Add(adornChar rune, overline bool, length int) int {
	lvl := s.Find(adornChar)
	if lvl > 0 {
		return lvl
	}
	*s = append(*s, sectionLevel{char: adornChar, overline: overline, length: length})
	return len(*s)
}

// Returns -1 if not found
func (s *sectionLevels) Find(adornChar rune) int {
	for lvl, sec := range *s {
		if sec.char == adornChar {
			return lvl + 1
		}
	}
	return -1
}

func (s *sectionLevels) Level() int {
	return len(*s)
}

// Parse is the entry point for the reStructuredText parser.
func Parse(name, text string) (t *Tree, errors []error) {
	t = New(name)
	t.text = text
	_, errors = t.Parse(text, t)
	return
}

func New(name string) *Tree {
	return &Tree{Name: name, sectionLevels: new(sectionLevels)}
}

type Tree struct {
	Name          string
	Nodes         *NodeList // The root node list
	Errors        []error
	text          string
	lex           *lexer
	peekCount     int
	token         [3]item        // three-token look-ahead for parser.
	sectionLevel  int            // The current section level of parsing
	sectionLevels *sectionLevels // Encountered section levels
	id            int            // The unique id of the node in the tree
}

func (t *Tree) errorf(format string, args ...interface{}) {
	format = fmt.Sprintf("go-rst: %s:%d: %s\n", t.Name, t.lex.lineNumber(), format)
	t.Errors = append(t.Errors, fmt.Errorf(format, args...))
}

func (t *Tree) error(err error) {
	t.errorf("%s\n", err)
}

// startParse initializes the parser, using the lexer.
func (t *Tree) startParse(lex *lexer) {
	t.Nodes = nil
	t.lex = lex
}

// stopParse terminates parsing.
func (t *Tree) stopParse() {
	t.lex = nil
}

func (t *Tree) Parse(text string, treeSet *Tree) (tree *Tree, errors []error) {
	log.Debugln("Start")
	t.startParse(lex(t.Name, text))
	t.text = text
	t.parse(treeSet)
	log.Debugln("End")
	return t, t.Errors
}

func (t *Tree) parse(tree *Tree) {
	log.Debugln("Start")

	t.Nodes = newList()

	nodeBranch := t.Nodes

	for t.peek().Type != itemEOF {
		var n Node
		token := t.next()
		log.Debugf("Got token: %#+v\n", token)
		switch token.Type {
		case itemTitle: // Section includes overline/underline
			n = t.section(token)
			log.Infof("New Node: %#+v\n", n)
		case itemBlankLine:
			n = newBlankLine(token, &t.id)
			log.Infof("New Node: %#+v\n", n)
		case itemParagraph:
			n = newParagraph(token, &t.id)
			log.Infof("New Node: %#+v\n", n)
		default:
			t.errorf("%q Not implemented!", token.Type)
			continue
		}

		nodeBranch.append(n)
		if n.NodeType() == NodeSection {
			nodeBranch =
			reflect.ValueOf(n).Elem().FieldByName("NodeList").Addr().Interface().(*NodeList)
		}
	}

	log.Debugln("End")
}

func (t *Tree) backup() {
	t.peekCount++
}

// peekBack returns the last item sent from the lexer.
func (t *Tree) peekBack() item {
	return *t.lex.lastItem
}

// peek returns but does not consume the next token.
func (t *Tree) peek() item {
	if t.peekCount > 0 {
		return t.token[t.peekCount-1]

	}
	t.peekCount = 1
	t.token[0] = t.lex.nextItem()
	return t.token[0]
}

func (t *Tree) next() item {
	if t.peekCount > 0 {
		t.peekCount--
	} else {
		t.token[0] = t.lex.nextItem()
	}
	return t.token[t.peekCount]
}

func (t *Tree) section(i item) Node {
	log.Debugln("Start")
	var overAdorn, title, underAdorn item
	var overline bool

	if t.peekBack().Type == itemSectionAdornment {
		overline = true
		overAdorn = t.peekBack()
	}

	title = i
	underAdorn = t.next() // Grab the section underline

	// Check adornment for proper syntax
	if title.Length != underAdorn.Length {
		t.errorf("Section under line  not equal to title length!")
	} else if overline && title.Length != overAdorn.Length {
		t.errorf("Section over line not equal to title length!")
	} else if overline && overAdorn.Text != underAdorn.Text {
		t.errorf("Section title over line does not match section title under line.")
	}

	// Check section levels to make sure the order of sections seen has not been violated
	if level := t.sectionLevels.Find(rune(underAdorn.Text.(string)[0])); level > 0 {
		if t.sectionLevel == t.sectionLevels.Level() {
			t.sectionLevel++
		} else {
			// The current section level of the parser does not match the previously
			// found section level. This means the user has used incorrect section
			// syntax.
			t.errorf("Incorrect section adornment \"%q\" for section level %d",
				underAdorn.Text.(string)[0], t.sectionLevel)
		}
	} else {
		t.sectionLevel++
	}

	t.sectionLevels.Add(rune(underAdorn.Text.(string)[0]), overline, len(underAdorn.Text.(string)))
	ret := newSection(title, &t.id, t.sectionLevel, overAdorn, underAdorn)

	log.Debugln("End")
	return ret
}
<commit_msg>parse.go: Update sectionLevels.String()<commit_after>// go-rst - A reStructuredText parser for Go
// 2014 (c) The go-rst Authors
// MIT Licensed. See LICENSE for details.

package parse

import (
	"fmt"
	"github.com/demizer/go-elog"
	"reflect"
)

type systemMessageLevel int

const (
	levelInfo systemMessageLevel = iota
	levelWarning
	levelError
	levelSevere
)

var systemMessageLevels = [...]string{
	"INFO",
	"WARNING",
	"ERROR",
	"SEVERE",
}

func (s systemMessageLevel) String() string {
	return systemMessageLevels[s]
}

type systemMessage struct {
	level  systemMessageLevel
	line   int
	source string
	items  []item
}

type sectionLevels []*SectionNode

func (s *sectionLevels) String() string {
	var out string
	for _, sec := range *s {
		out += fmt.Sprintf("level: %d, rune: %q, overline: %t, length: %d\n",
			sec.Level, sec.UnderLine.Rune, sec.OverLine != nil, sec.Length)
	}
	return out
}

func (s *sectionLevels) Add(adornChar rune, overline bool, length int) int {
	lvl := s.Find(adornChar)
	if lvl > 0 {
		return lvl
	}
	*s = append(*s, sectionLevel{char: adornChar, overline: overline, length: length})
	return len(*s)
}

// Returns -1 if not found
func (s *sectionLevels) Find(adornChar rune) int {
	for lvl, sec := range *s {
		if sec.char == adornChar {
			return lvl + 1
		}
	}
	return -1
}

func (s *sectionLevels) Level() int {
	return len(*s)
}

// Parse is the entry point for the reStructuredText parser.
func Parse(name, text string) (t *Tree, errors []error) {
	t = New(name)
	t.text = text
	_, errors = t.Parse(text, t)
	return
}

func New(name string) *Tree {
	return &Tree{Name: name, sectionLevels: new(sectionLevels)}
}

type Tree struct {
	Name          string
	Nodes         *NodeList // The root node list
	Errors        []error
	text          string
	lex           *lexer
	peekCount     int
	token         [3]item        // three-token look-ahead for parser.
	sectionLevel  int            // The current section level of parsing
	sectionLevels *sectionLevels // Encountered section levels
	id            int            // The unique id of the node in the tree
}

func (t *Tree) errorf(format string, args ...interface{}) {
	format = fmt.Sprintf("go-rst: %s:%d: %s\n", t.Name, t.lex.lineNumber(), format)
	t.Errors = append(t.Errors, fmt.Errorf(format, args...))
}

func (t *Tree) error(err error) {
	t.errorf("%s\n", err)
}

// startParse initializes the parser, using the lexer.
func (t *Tree) startParse(lex *lexer) {
	t.Nodes = nil
	t.lex = lex
}

// stopParse terminates parsing.
func (t *Tree) stopParse() {
	t.lex = nil
}

func (t *Tree) Parse(text string, treeSet *Tree) (tree *Tree, errors []error) {
	log.Debugln("Start")
	t.startParse(lex(t.Name, text))
	t.text = text
	t.parse(treeSet)
	log.Debugln("End")
	return t, t.Errors
}

func (t *Tree) parse(tree *Tree) {
	log.Debugln("Start")

	t.Nodes = newList()

	nodeBranch := t.Nodes

	for t.peek().Type != itemEOF {
		var n Node
		token := t.next()
		log.Debugf("Got token: %#+v\n", token)
		switch token.Type {
		case itemTitle: // Section includes overline/underline
			n = t.section(token)
			log.Infof("New Node: %#+v\n", n)
		case itemBlankLine:
			n = newBlankLine(token, &t.id)
			log.Infof("New Node: %#+v\n", n)
		case itemParagraph:
			n = newParagraph(token, &t.id)
			log.Infof("New Node: %#+v\n", n)
		default:
			t.errorf("%q Not implemented!", token.Type)
			continue
		}

		nodeBranch.append(n)
		if n.NodeType() == NodeSection {
			nodeBranch =
			reflect.ValueOf(n).Elem().FieldByName("NodeList").Addr().Interface().(*NodeList)
		}
	}

	log.Debugln("End")
}

func (t *Tree) backup() {
	t.peekCount++
}

// peekBack returns the last item sent from the lexer.
func (t *Tree) peekBack() item {
	return *t.lex.lastItem
}

// peek returns but does not consume the next token.
func (t *Tree) peek() item {
	if t.peekCount > 0 {
		return t.token[t.peekCount-1]

	}
	t.peekCount = 1
	t.token[0] = t.lex.nextItem()
	return t.token[0]
}

func (t *Tree) next() item {
	if t.peekCount > 0 {
		t.peekCount--
	} else {
		t.token[0] = t.lex.nextItem()
	}
	return t.token[t.peekCount]
}

func (t *Tree) section(i item) Node {
	log.Debugln("Start")
	var overAdorn, title, underAdorn item
	var overline bool

	if t.peekBack().Type == itemSectionAdornment {
		overline = true
		overAdorn = t.peekBack()
	}

	title = i
	underAdorn = t.next() // Grab the section underline

	// Check adornment for proper syntax
	if title.Length != underAdorn.Length {
		t.errorf("Section under line  not equal to title length!")
	} else if overline && title.Length != overAdorn.Length {
		t.errorf("Section over line not equal to title length!")
	} else if overline && overAdorn.Text != underAdorn.Text {
		t.errorf("Section title over line does not match section title under line.")
	}

	// Check section levels to make sure the order of sections seen has not been violated
	if level := t.sectionLevels.Find(rune(underAdorn.Text.(string)[0])); level > 0 {
		if t.sectionLevel == t.sectionLevels.Level() {
			t.sectionLevel++
		} else {
			// The current section level of the parser does not match the previously
			// found section level. This means the user has used incorrect section
			// syntax.
			t.errorf("Incorrect section adornment \"%q\" for section level %d",
				underAdorn.Text.(string)[0], t.sectionLevel)
		}
	} else {
		t.sectionLevel++
	}

	t.sectionLevels.Add(rune(underAdorn.Text.(string)[0]), overline, len(underAdorn.Text.(string)))
	ret := newSection(title, &t.id, t.sectionLevel, overAdorn, underAdorn)

	log.Debugln("End")
	return ret
}
<|endoftext|>


<commit_before>package variablelengthquantity

import (
	"bytes"
	"testing"
)

/*
The goal of this exercise is to implement
VLQ encoding/decoding as described here: https://en.wikipedia.org/wiki/Variable-length_quantity

In short, the goal of this encoding is to save encode integer values in a way that would save bytes.
Only the first 7 bits of each byte is significant (right-justified; sort of like an ASCII byte).
So, if you have a 32-bit value, you have to unpack it into a series of 7-bit bytes.
Of course, you will have a variable number of bytes depending upon your integer.
To indicate which is the last byte of the series, you leave bit #7 clear.
In all of the preceding bytes, you set bit #7.

So, if an integer is between `0-127`, it can be represented as one byte.
The largest integer allowed is `0FFFFFFF`, which translates to 4 bytes variable length.
Here are examples of delta-times as 32-bit values, and the variable length quantities that they translate to:
*/

func TestEncodeDecodeVarint(t *testing.T) {
	testCases := []struct {
		input  []byte
		output uint32
	}{
		0: {[]byte{0x7F}, 127},
		1: {[]byte{0x81, 0x00}, 128},
		2: {[]byte{0xC0, 0x00}, 8192},
		3: {[]byte{0xFF, 0x7F}, 16383},
		4: {[]byte{0x81, 0x80, 0x00}, 16384},
		5: {[]byte{0xFF, 0xFF, 0x7F}, 2097151},
		6: {[]byte{0x81, 0x80, 0x80, 0x00}, 2097152},
		7: {[]byte{0xC0, 0x80, 0x80, 0x00}, 134217728},
		8: {[]byte{0xFF, 0xFF, 0xFF, 0x7F}, 268435455},

		9:  {[]byte{0x82, 0x00}, 256},
		10: {[]byte{0x81, 0x10}, 144},
	}

	for i, tc := range testCases {
		t.Logf("test case %d - %#v\n", i, tc.input)
		if o, _ := DecodeVarint(tc.input); o != tc.output {
			t.Fatalf("expected %d\ngot\n%d\n", tc.output, o)
		}
		if encoded := EncodeVarint(tc.output); bytes.Compare(encoded, tc.input) != 0 {
			t.Fatalf("%d - expected %#v\ngot\n%#v\n", tc.output, tc.input, encoded)
		}
	}
}
<commit_msg>remove the test/exercise documentation from the exercise since it will be moved to the problem<commit_after>package variablelengthquantity

import (
	"bytes"
	"testing"
)

func TestEncodeDecodeVarint(t *testing.T) {
	testCases := []struct {
		input  []byte
		output uint32
	}{
		0: {[]byte{0x7F}, 127},
		1: {[]byte{0x81, 0x00}, 128},
		2: {[]byte{0xC0, 0x00}, 8192},
		3: {[]byte{0xFF, 0x7F}, 16383},
		4: {[]byte{0x81, 0x80, 0x00}, 16384},
		5: {[]byte{0xFF, 0xFF, 0x7F}, 2097151},
		6: {[]byte{0x81, 0x80, 0x80, 0x00}, 2097152},
		7: {[]byte{0xC0, 0x80, 0x80, 0x00}, 134217728},
		8: {[]byte{0xFF, 0xFF, 0xFF, 0x7F}, 268435455},

		9:  {[]byte{0x82, 0x00}, 256},
		10: {[]byte{0x81, 0x10}, 144},
	}

	for i, tc := range testCases {
		t.Logf("test case %d - %#v\n", i, tc.input)
		if o, _ := DecodeVarint(tc.input); o != tc.output {
			t.Fatalf("expected %d\ngot\n%d\n", tc.output, o)
		}
		if encoded := EncodeVarint(tc.output); bytes.Compare(encoded, tc.input) != 0 {
			t.Fatalf("%d - expected %#v\ngot\n%#v\n", tc.output, tc.input, encoded)
		}
	}
}
<|endoftext|>


<commit_before>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2016 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package lib

import (
	"context"
	"github.com/stretchr/testify/assert"
	"gopkg.in/guregu/null.v3"
	"runtime"
	"testing"
	"time"
)

// Helper for asserting the number of active/dead VUs.
func assertActiveVUs(t *testing.T, e *Engine, active, dead int) {
	var numActive, numDead int
	var lastWasDead bool
	for _, vu := range e.vuEntries {
		if vu.Cancel != nil {
			numActive++
			assert.False(t, lastWasDead, "living vu in dead zone")
		} else {
			numDead++
			lastWasDead = true
		}
	}
	assert.Equal(t, active, numActive, "wrong number of active vus")
	assert.Equal(t, dead, numDead, "wrong number of dead vus")
}

func TestNewEngine(t *testing.T) {
	_, err := NewEngine(nil, Options{})
	assert.NoError(t, err)
}

func TestNewEngineOptions(t *testing.T) {
	t.Run("VUsMax", func(t *testing.T) {
		t.Run("not set", func(t *testing.T) {
			e, err := NewEngine(nil, Options{})
			assert.NoError(t, err)
			assert.Equal(t, int64(0), e.GetVUsMax())
			assert.Equal(t, int64(0), e.GetVUs())
		})
		t.Run("set", func(t *testing.T) {
			e, err := NewEngine(nil, Options{
				VUsMax: null.IntFrom(10),
			})
			assert.NoError(t, err)
			assert.Equal(t, int64(10), e.GetVUsMax())
			assert.Equal(t, int64(0), e.GetVUs())
		})
	})
	t.Run("VUs", func(t *testing.T) {
		t.Run("no max", func(t *testing.T) {
			_, err := NewEngine(nil, Options{
				VUs: null.IntFrom(10),
			})
			assert.EqualError(t, err, "more vus than allocated requested")
		})
		t.Run("max too low", func(t *testing.T) {
			_, err := NewEngine(nil, Options{
				VUsMax: null.IntFrom(1),
				VUs:    null.IntFrom(10),
			})
			assert.EqualError(t, err, "more vus than allocated requested")
		})
		t.Run("max higher", func(t *testing.T) {
			e, err := NewEngine(nil, Options{
				VUsMax: null.IntFrom(10),
				VUs:    null.IntFrom(1),
			})
			assert.NoError(t, err)
			assert.Equal(t, int64(10), e.GetVUsMax())
			assert.Equal(t, int64(1), e.GetVUs())
		})
		t.Run("max just right", func(t *testing.T) {
			e, err := NewEngine(nil, Options{
				VUsMax: null.IntFrom(10),
				VUs:    null.IntFrom(10),
			})
			assert.NoError(t, err)
			assert.Equal(t, int64(10), e.GetVUsMax())
			assert.Equal(t, int64(10), e.GetVUs())
		})
	})
	t.Run("Paused", func(t *testing.T) {
		t.Run("not set", func(t *testing.T) {
			e, err := NewEngine(nil, Options{})
			assert.NoError(t, err)
			assert.False(t, e.IsPaused())
		})
		t.Run("false", func(t *testing.T) {
			e, err := NewEngine(nil, Options{
				Paused: null.BoolFrom(false),
			})
			assert.NoError(t, err)
			assert.False(t, e.IsPaused())
		})
		t.Run("true", func(t *testing.T) {
			e, err := NewEngine(nil, Options{
				Paused: null.BoolFrom(true),
			})
			assert.NoError(t, err)
			assert.True(t, e.IsPaused())
		})
	})
}

func TestEngineRun(t *testing.T) {
	t.Run("exits with context", func(t *testing.T) {
		startTime := time.Now()
		duration := 100 * time.Millisecond
		e, err := NewEngine(nil, Options{})
		assert.NoError(t, err)

		ctx, _ := context.WithTimeout(context.Background(), duration)
		assert.NoError(t, e.Run(ctx))
		assert.WithinDuration(t, startTime.Add(duration), time.Now(), 100*time.Millisecond)
	})
	t.Run("terminates subctx", func(t *testing.T) {
		e, err := NewEngine(nil, Options{})
		assert.NoError(t, err)

		subctx := e.subctx
		select {
		case <-subctx.Done():
			assert.Fail(t, "context is already terminated")
		default:
		}

		ctx, cancel := context.WithCancel(context.Background())
		cancel()
		assert.NoError(t, e.Run(ctx))

		assert.NotEqual(t, subctx, e.subctx, "subcontext not changed")
		select {
		case <-subctx.Done():
		default:
			assert.Fail(t, "context was not terminated")
		}
	})
	t.Run("updates AtTime", func(t *testing.T) {
		e, err := NewEngine(nil, Options{})
		assert.NoError(t, err)

		d := 50 * time.Millisecond
		ctx, _ := context.WithTimeout(context.Background(), d)
		startTime := time.Now()
		assert.NoError(t, e.Run(ctx))
		assert.WithinDuration(t, startTime.Add(d), startTime.Add(e.AtTime()), 2*TickRate)
	})
}

func TestEngineIsRunning(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	e, err := NewEngine(nil, Options{})
	assert.NoError(t, err)

	go func() { assert.NoError(t, e.Run(ctx)) }()
	runtime.Gosched()
	time.Sleep(1 * time.Millisecond)
	assert.True(t, e.IsRunning())

	cancel()
	runtime.Gosched()
	time.Sleep(1 * time.Millisecond)
	assert.False(t, e.IsRunning())
}

func TestEngineSetPaused(t *testing.T) {
	e, err := NewEngine(nil, Options{})
	assert.NoError(t, err)
	assert.False(t, e.IsPaused())

	e.SetPaused(true)
	assert.True(t, e.IsPaused())

	e.SetPaused(false)
	assert.False(t, e.IsPaused())
}

func TestEngineSetVUsMax(t *testing.T) {
	t.Run("not set", func(t *testing.T) {
		e, err := NewEngine(nil, Options{})
		assert.NoError(t, err)
		assert.Equal(t, int64(0), e.GetVUsMax())
		assert.Len(t, e.vuEntries, 0)
	})
	t.Run("set", func(t *testing.T) {
		e, err := NewEngine(nil, Options{})
		assert.NoError(t, err)
		assert.NoError(t, e.SetVUsMax(10))
		assert.Equal(t, int64(10), e.GetVUsMax())
		assert.Len(t, e.vuEntries, 10)
		for _, vu := range e.vuEntries {
			assert.Nil(t, vu.Cancel)
		}

		t.Run("higher", func(t *testing.T) {
			assert.NoError(t, e.SetVUsMax(15))
			assert.Equal(t, int64(15), e.GetVUsMax())
			assert.Len(t, e.vuEntries, 15)
			for _, vu := range e.vuEntries {
				assert.Nil(t, vu.Cancel)
			}
		})

		t.Run("lower", func(t *testing.T) {
			assert.NoError(t, e.SetVUsMax(5))
			assert.Equal(t, int64(5), e.GetVUsMax())
			assert.Len(t, e.vuEntries, 5)
			for _, vu := range e.vuEntries {
				assert.Nil(t, vu.Cancel)
			}
		})
	})
	t.Run("set negative", func(t *testing.T) {
		e, err := NewEngine(nil, Options{})
		assert.NoError(t, err)
		assert.EqualError(t, e.SetVUsMax(-1), "vus-max can't be negative")
		assert.Len(t, e.vuEntries, 0)
	})
	t.Run("set too low", func(t *testing.T) {
		e, err := NewEngine(nil, Options{
			VUsMax: null.IntFrom(10),
			VUs:    null.IntFrom(10),
		})
		assert.NoError(t, err)
		assert.EqualError(t, e.SetVUsMax(5), "can't reduce vus-max below vus")
		assert.Len(t, e.vuEntries, 10)
	})
}

func TestEngineSetVUs(t *testing.T) {
	t.Run("not set", func(t *testing.T) {
		e, err := NewEngine(nil, Options{})
		assert.NoError(t, err)
		assert.Equal(t, int64(0), e.GetVUsMax())
		assert.Equal(t, int64(0), e.GetVUs())
	})
	t.Run("set", func(t *testing.T) {
		e, err := NewEngine(nil, Options{VUsMax: null.IntFrom(15)})
		assert.NoError(t, err)
		assert.NoError(t, e.SetVUs(10))
		assert.Equal(t, int64(10), e.GetVUs())
		assertActiveVUs(t, e, 10, 5)

		t.Run("negative", func(t *testing.T) {
			assert.EqualError(t, e.SetVUs(-1), "vus can't be negative")
			assert.Equal(t, int64(10), e.GetVUs())
			assertActiveVUs(t, e, 10, 5)
		})

		t.Run("too high", func(t *testing.T) {
			assert.EqualError(t, e.SetVUs(20), "more vus than allocated requested")
			assert.Equal(t, int64(10), e.GetVUs())
			assertActiveVUs(t, e, 10, 5)
		})

		t.Run("lower", func(t *testing.T) {
			assert.NoError(t, e.SetVUs(5))
			assert.Equal(t, int64(5), e.GetVUs())
			assertActiveVUs(t, e, 5, 10)
		})

		t.Run("higher", func(t *testing.T) {
			assert.NoError(t, e.SetVUs(15))
			assert.Equal(t, int64(15), e.GetVUs())
			assertActiveVUs(t, e, 15, 0)
		})
	})
}
<commit_msg>[test/refactor] This should be its own test<commit_after>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2016 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package lib

import (
	"context"
	"github.com/stretchr/testify/assert"
	"gopkg.in/guregu/null.v3"
	"runtime"
	"testing"
	"time"
)

// Helper for asserting the number of active/dead VUs.
func assertActiveVUs(t *testing.T, e *Engine, active, dead int) {
	var numActive, numDead int
	var lastWasDead bool
	for _, vu := range e.vuEntries {
		if vu.Cancel != nil {
			numActive++
			assert.False(t, lastWasDead, "living vu in dead zone")
		} else {
			numDead++
			lastWasDead = true
		}
	}
	assert.Equal(t, active, numActive, "wrong number of active vus")
	assert.Equal(t, dead, numDead, "wrong number of dead vus")
}

func TestNewEngine(t *testing.T) {
	_, err := NewEngine(nil, Options{})
	assert.NoError(t, err)
}

func TestNewEngineOptions(t *testing.T) {
	t.Run("VUsMax", func(t *testing.T) {
		t.Run("not set", func(t *testing.T) {
			e, err := NewEngine(nil, Options{})
			assert.NoError(t, err)
			assert.Equal(t, int64(0), e.GetVUsMax())
			assert.Equal(t, int64(0), e.GetVUs())
		})
		t.Run("set", func(t *testing.T) {
			e, err := NewEngine(nil, Options{
				VUsMax: null.IntFrom(10),
			})
			assert.NoError(t, err)
			assert.Equal(t, int64(10), e.GetVUsMax())
			assert.Equal(t, int64(0), e.GetVUs())
		})
	})
	t.Run("VUs", func(t *testing.T) {
		t.Run("no max", func(t *testing.T) {
			_, err := NewEngine(nil, Options{
				VUs: null.IntFrom(10),
			})
			assert.EqualError(t, err, "more vus than allocated requested")
		})
		t.Run("max too low", func(t *testing.T) {
			_, err := NewEngine(nil, Options{
				VUsMax: null.IntFrom(1),
				VUs:    null.IntFrom(10),
			})
			assert.EqualError(t, err, "more vus than allocated requested")
		})
		t.Run("max higher", func(t *testing.T) {
			e, err := NewEngine(nil, Options{
				VUsMax: null.IntFrom(10),
				VUs:    null.IntFrom(1),
			})
			assert.NoError(t, err)
			assert.Equal(t, int64(10), e.GetVUsMax())
			assert.Equal(t, int64(1), e.GetVUs())
		})
		t.Run("max just right", func(t *testing.T) {
			e, err := NewEngine(nil, Options{
				VUsMax: null.IntFrom(10),
				VUs:    null.IntFrom(10),
			})
			assert.NoError(t, err)
			assert.Equal(t, int64(10), e.GetVUsMax())
			assert.Equal(t, int64(10), e.GetVUs())
		})
	})
	t.Run("Paused", func(t *testing.T) {
		t.Run("not set", func(t *testing.T) {
			e, err := NewEngine(nil, Options{})
			assert.NoError(t, err)
			assert.False(t, e.IsPaused())
		})
		t.Run("false", func(t *testing.T) {
			e, err := NewEngine(nil, Options{
				Paused: null.BoolFrom(false),
			})
			assert.NoError(t, err)
			assert.False(t, e.IsPaused())
		})
		t.Run("true", func(t *testing.T) {
			e, err := NewEngine(nil, Options{
				Paused: null.BoolFrom(true),
			})
			assert.NoError(t, err)
			assert.True(t, e.IsPaused())
		})
	})
}

func TestEngineRun(t *testing.T) {
	t.Run("exits with context", func(t *testing.T) {
		startTime := time.Now()
		duration := 100 * time.Millisecond
		e, err := NewEngine(nil, Options{})
		assert.NoError(t, err)

		ctx, _ := context.WithTimeout(context.Background(), duration)
		assert.NoError(t, e.Run(ctx))
		assert.WithinDuration(t, startTime.Add(duration), time.Now(), 100*time.Millisecond)
	})
	t.Run("terminates subctx", func(t *testing.T) {
		e, err := NewEngine(nil, Options{})
		assert.NoError(t, err)

		subctx := e.subctx
		select {
		case <-subctx.Done():
			assert.Fail(t, "context is already terminated")
		default:
		}

		ctx, cancel := context.WithCancel(context.Background())
		cancel()
		assert.NoError(t, e.Run(ctx))

		assert.NotEqual(t, subctx, e.subctx, "subcontext not changed")
		select {
		case <-subctx.Done():
		default:
			assert.Fail(t, "context was not terminated")
		}
	})
}

func TestEngineIsRunning(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	e, err := NewEngine(nil, Options{})
	assert.NoError(t, err)

	go func() { assert.NoError(t, e.Run(ctx)) }()
	runtime.Gosched()
	time.Sleep(1 * time.Millisecond)
	assert.True(t, e.IsRunning())

	cancel()
	runtime.Gosched()
	time.Sleep(1 * time.Millisecond)
	assert.False(t, e.IsRunning())
}

func TestEngineAtTime(t *testing.T) {
	e, err := NewEngine(nil, Options{})
	assert.NoError(t, err)

	d := 50 * time.Millisecond
	ctx, _ := context.WithTimeout(context.Background(), d)
	startTime := time.Now()
	assert.NoError(t, e.Run(ctx))
	assert.WithinDuration(t, startTime.Add(d), startTime.Add(e.AtTime()), 2*TickRate)
}

func TestEngineSetPaused(t *testing.T) {
	e, err := NewEngine(nil, Options{})
	assert.NoError(t, err)
	assert.False(t, e.IsPaused())

	e.SetPaused(true)
	assert.True(t, e.IsPaused())

	e.SetPaused(false)
	assert.False(t, e.IsPaused())
}

func TestEngineSetVUsMax(t *testing.T) {
	t.Run("not set", func(t *testing.T) {
		e, err := NewEngine(nil, Options{})
		assert.NoError(t, err)
		assert.Equal(t, int64(0), e.GetVUsMax())
		assert.Len(t, e.vuEntries, 0)
	})
	t.Run("set", func(t *testing.T) {
		e, err := NewEngine(nil, Options{})
		assert.NoError(t, err)
		assert.NoError(t, e.SetVUsMax(10))
		assert.Equal(t, int64(10), e.GetVUsMax())
		assert.Len(t, e.vuEntries, 10)
		for _, vu := range e.vuEntries {
			assert.Nil(t, vu.Cancel)
		}

		t.Run("higher", func(t *testing.T) {
			assert.NoError(t, e.SetVUsMax(15))
			assert.Equal(t, int64(15), e.GetVUsMax())
			assert.Len(t, e.vuEntries, 15)
			for _, vu := range e.vuEntries {
				assert.Nil(t, vu.Cancel)
			}
		})

		t.Run("lower", func(t *testing.T) {
			assert.NoError(t, e.SetVUsMax(5))
			assert.Equal(t, int64(5), e.GetVUsMax())
			assert.Len(t, e.vuEntries, 5)
			for _, vu := range e.vuEntries {
				assert.Nil(t, vu.Cancel)
			}
		})
	})
	t.Run("set negative", func(t *testing.T) {
		e, err := NewEngine(nil, Options{})
		assert.NoError(t, err)
		assert.EqualError(t, e.SetVUsMax(-1), "vus-max can't be negative")
		assert.Len(t, e.vuEntries, 0)
	})
	t.Run("set too low", func(t *testing.T) {
		e, err := NewEngine(nil, Options{
			VUsMax: null.IntFrom(10),
			VUs:    null.IntFrom(10),
		})
		assert.NoError(t, err)
		assert.EqualError(t, e.SetVUsMax(5), "can't reduce vus-max below vus")
		assert.Len(t, e.vuEntries, 10)
	})
}

func TestEngineSetVUs(t *testing.T) {
	t.Run("not set", func(t *testing.T) {
		e, err := NewEngine(nil, Options{})
		assert.NoError(t, err)
		assert.Equal(t, int64(0), e.GetVUsMax())
		assert.Equal(t, int64(0), e.GetVUs())
	})
	t.Run("set", func(t *testing.T) {
		e, err := NewEngine(nil, Options{VUsMax: null.IntFrom(15)})
		assert.NoError(t, err)
		assert.NoError(t, e.SetVUs(10))
		assert.Equal(t, int64(10), e.GetVUs())
		assertActiveVUs(t, e, 10, 5)

		t.Run("negative", func(t *testing.T) {
			assert.EqualError(t, e.SetVUs(-1), "vus can't be negative")
			assert.Equal(t, int64(10), e.GetVUs())
			assertActiveVUs(t, e, 10, 5)
		})

		t.Run("too high", func(t *testing.T) {
			assert.EqualError(t, e.SetVUs(20), "more vus than allocated requested")
			assert.Equal(t, int64(10), e.GetVUs())
			assertActiveVUs(t, e, 10, 5)
		})

		t.Run("lower", func(t *testing.T) {
			assert.NoError(t, e.SetVUs(5))
			assert.Equal(t, int64(5), e.GetVUs())
			assertActiveVUs(t, e, 5, 10)
		})

		t.Run("higher", func(t *testing.T) {
			assert.NoError(t, e.SetVUs(15))
			assert.Equal(t, int64(15), e.GetVUs())
			assertActiveVUs(t, e, 15, 0)
		})
	})
}
<|endoftext|>


<commit_before>/*
Author: Mathieu Mailhos
Filename: logger.go
Description: Set the parameters for the logger. It is a home-made logger that also keep tracks of the count of hashes for a easier debugging. The purpose is not to re-write 'log' library but to use it and to include some measurements from the mining pool.
*/

package logger

import (
	"gobtcminer/config"
	"log"
	"sync"
	"time"
)

//Logger object.
type Logger struct {
	Activated  bool       //Can be activatede, or not.
	Level      string     //Levels: 'debug' and 'info'
	File       string     //Filename for storing the output
	HashCount  uint32     //Global count of hashes executed so far
	BlockCount uint32     //Global count of hashes executed so far
	mux        sync.Mutex //Mutex for avoiding concurrency on increasing HashCount
	BeginTime  time.Time  //Used for calculating the compute time for benchmarking
}

//NewLogger Constructor function
func NewLogger(logger config.JSONLogger) Logger {
	return Logger{
		Activated: logger.Activated,
		Level:     logger.Level,
		File:      logger.File}
}

//Print simply logs
func (logger *Logger) Print(level string, output string) {
	if logger.Activated {
		if logger.Level == level {
			log.Println(output)
		} else if logger.Level == "debug" && level == "info" {
			log.Println(output)
		}
	}
}

//IncrementHashCount counts the number of hash executed regularly. Use of a mutex to avoid race condition.
func (logger *Logger) IncrementHashCount(count uint32) {
	logger.mux.Lock()
	defer logger.mux.Unlock()
	logger.HashCount += count
}

//IncrementBlockCount increments the number of succesfuly mined block. Use of a mutex to avoid race condition.
func (logger *Logger) IncrementBlockCount() {
	logger.mux.Lock()
	defer logger.mux.Unlock()
	logger.BlockCount++
}
<commit_msg>chore(logger): syntax fix<commit_after>/*
Author: Mathieu Mailhos
Filename: logger.go
Description: Set the parameters for the logger. It is a home-made logger that also keep tracks of the count of hashes for a easier debugging. The purpose is not to re-write 'log' library but to use it and to include some measurements from the mining pool.
*/

package logger

import (
	"gobtcminer/config"
	"log"
	"sync"
	"time"
)

//Logger object.
type Logger struct {
	Activated  bool       //Can be activatede, or not.
	Level      string     //Levels: 'debug' and 'info'
	File       string     //Filename for storing the output
	HashCount  uint32     //Global count of hashes executed so far
	BlockCount uint32     //Global count of hashes executed so far
	mux        sync.Mutex //Mutex for avoiding concurrency on increasing HashCount
	BeginTime  time.Time  //Used for calculating the compute time for benchmarking
}

//NewLogger Constructor function
func NewLogger(logger config.JSONLogger) Logger {
	return Logger{
		Activated: logger.Activated,
		Level:     logger.Level,
		File:      logger.File,
	}
}

//Print simply logs
func (logger *Logger) Print(level string, output string) {
	if logger.Activated {
		if logger.Level == level {
			log.Println(output)
		} else if logger.Level == "debug" && level == "info" {
			log.Println(output)
		}
	}
}

//IncrementHashCount counts the number of hash executed regularly. Use of a mutex to avoid race condition.
func (logger *Logger) IncrementHashCount(count uint32) {
	logger.mux.Lock()
	defer logger.mux.Unlock()
	logger.HashCount += count
}

//IncrementBlockCount increments the number of succesfuly mined block. Use of a mutex to avoid race condition.
func (logger *Logger) IncrementBlockCount() {
	logger.mux.Lock()
	defer logger.mux.Unlock()
	logger.BlockCount++
}
<|endoftext|>


<commit_before>package kafka

import (
	"bytes"
	"fmt"
	"log"
	"time"

	"github.com/Shopify/sarama"
	"github.com/bsm/sarama-cluster"
	"github.com/dollarshaveclub/furan/generated/lib"
	"github.com/dollarshaveclub/furan/lib/metrics"
	"github.com/gocql/gocql"
	"github.com/golang/protobuf/proto"
)

const (
	maxFlushMsgs       = 5
	maxFlushFreqSecs   = 1
	connectTimeoutSecs = 10
	keepaliveSecs      = 5
)

var kafkaVersion = sarama.V0_10_0_0

// EventBusProducer describes an object capable of publishing events somewhere
type EventBusProducer interface {
	PublishEvent(*lib.BuildEvent) error
}

// EventBusConsumer describes an object cabable of subscribing to events somewhere
type EventBusConsumer interface {
	SubscribeToTopic(chan<- *lib.BuildEvent, <-chan struct{}, gocql.UUID) error
}

// EventBusManager describes an object that can publish and subscribe to events somewhere
type EventBusManager interface {
	EventBusProducer
	EventBusConsumer
}

// KafkaManager handles sending event messages to the configured Kafka topic
type KafkaManager struct {
	ap           sarama.AsyncProducer
	topic        string
	brokers      []string
	consumerConf *cluster.Config
	mc           metrics.MetricsCollector
	logger       *log.Logger
}

// NewKafkaManager returns a new Kafka manager object
func NewKafkaManager(brokers []string, topic string, maxsends uint, mc metrics.MetricsCollector, logger *log.Logger) (*KafkaManager, error) {
	pconf := sarama.NewConfig()
	pconf.Version = kafkaVersion

	pconf.Net.MaxOpenRequests = int(maxsends)
	pconf.Net.DialTimeout = connectTimeoutSecs * time.Second
	pconf.Net.ReadTimeout = connectTimeoutSecs * time.Second
	pconf.Net.WriteTimeout = connectTimeoutSecs * time.Second
	pconf.Net.KeepAlive = keepaliveSecs * time.Second

	pconf.Producer.Return.Errors = true
	pconf.Producer.Flush.Messages = maxFlushMsgs
	pconf.Producer.Flush.Frequency = maxFlushFreqSecs * time.Second

	asyncp, err := sarama.NewAsyncProducer(brokers, pconf)
	if err != nil {
		return nil, err
	}

	cconf := cluster.NewConfig()
	cconf.Version = pconf.Version
	cconf.Net = pconf.Net
	cconf.Consumer.Return.Errors = true

	kp := &KafkaManager{
		ap:           asyncp,
		topic:        topic,
		brokers:      brokers,
		consumerConf: cconf,
		mc:           mc,
		logger:       logger,
	}
	go kp.handlePErrors()
	return kp, nil
}

func (kp *KafkaManager) handlePErrors() {
	var kerr *sarama.ProducerError
	for {
		kerr = <-kp.ap.Errors()
		log.Printf("Kafka producer error: %v", kerr)
		kp.mc.KafkaProducerFailure()
	}
}

// PublishEvent publishes a build event to the configured Kafka topic
func (kp *KafkaManager) PublishEvent(event *lib.BuildEvent) error {
	id, err := gocql.ParseUUID(event.BuildId)
	if err != nil {
		return err
	}
	val, err := proto.Marshal(event)
	if err != nil {
		return fmt.Errorf("error marshaling protobuf: %v", err)
	}
	pmsg := &sarama.ProducerMessage{
		Topic: kp.topic,
		Key:   sarama.ByteEncoder(id.Bytes()), // Key is build ID to preserve event order (all events of a build go to the same partition)
		Value: sarama.ByteEncoder(val),
	}
	select { // don't block if Kafka is unavailable for some reason
	case kp.ap.Input() <- pmsg:
		return nil
	default:
		kp.mc.KafkaProducerFailure()
		return fmt.Errorf("could not publish Kafka message: channel full")
	}
}

// SubscribeToTopic listens to the configured topic, filters by build_id and writes
// the resulting messages to output. When the subscribed build is finished
// output is closed. done is a signal from the caller to abort the stream subscription
func (kp *KafkaManager) SubscribeToTopic(output chan<- *lib.BuildEvent, done <-chan struct{}, buildID gocql.UUID) error {
	// random group ID for each connection
	groupid, err := gocql.RandomUUID()
	if err != nil {
		return err
	}
	con, err := cluster.NewConsumer(kp.brokers, groupid.String(), []string{kp.topic}, kp.consumerConf)
	if err != nil {
		return err
	}
	handleConsumerErrors := func() {
		var err error
		for {
			err = <-con.Errors()
			if err == nil { // chan closed
				return
			}
			kp.mc.KafkaConsumerFailure()
			kp.logger.Printf("Kafka consumer error: %v", err)
		}
	}
	go handleConsumerErrors()
	go func() {
		defer close(output)
		defer con.Close()
		var err error
		var msg *sarama.ConsumerMessage
		var event *lib.BuildEvent
		input := con.Messages()
		for {
			select {
			case <-done:
				kp.logger.Printf("SubscribeToTopic: aborting")
				return
			default:
				break
			}
			msg = <-input
			if msg == nil {
				return
			}
			if bytes.Equal(msg.Key, []byte(buildID[:])) {
				event = &lib.BuildEvent{}
				err = proto.Unmarshal(msg.Value, event)
				if err != nil {
					kp.logger.Printf("%v: error unmarshaling event from Kafka stream: %v", buildID.String(), err)
					continue
				}
				output <- event
				if event.BuildFinished || event.EventError.IsError {
					return
				}
			}
		}
	}()
	return nil
}
<commit_msg>Use most recent Kafka version<commit_after>package kafka

import (
	"bytes"
	"fmt"
	"log"
	"time"

	"github.com/Shopify/sarama"
	"github.com/bsm/sarama-cluster"
	"github.com/dollarshaveclub/furan/generated/lib"
	"github.com/dollarshaveclub/furan/lib/metrics"
	"github.com/gocql/gocql"
	"github.com/golang/protobuf/proto"
)

const (
	maxFlushMsgs       = 5
	maxFlushFreqSecs   = 1
	connectTimeoutSecs = 10
	keepaliveSecs      = 5
)

var kafkaVersion = sarama.V1_0_0_0

// EventBusProducer describes an object capable of publishing events somewhere
type EventBusProducer interface {
	PublishEvent(*lib.BuildEvent) error
}

// EventBusConsumer describes an object cabable of subscribing to events somewhere
type EventBusConsumer interface {
	SubscribeToTopic(chan<- *lib.BuildEvent, <-chan struct{}, gocql.UUID) error
}

// EventBusManager describes an object that can publish and subscribe to events somewhere
type EventBusManager interface {
	EventBusProducer
	EventBusConsumer
}

// KafkaManager handles sending event messages to the configured Kafka topic
type KafkaManager struct {
	ap           sarama.AsyncProducer
	topic        string
	brokers      []string
	consumerConf *cluster.Config
	mc           metrics.MetricsCollector
	logger       *log.Logger
}

// NewKafkaManager returns a new Kafka manager object
func NewKafkaManager(brokers []string, topic string, maxsends uint, mc metrics.MetricsCollector, logger *log.Logger) (*KafkaManager, error) {
	pconf := sarama.NewConfig()
	pconf.Version = kafkaVersion

	pconf.Net.MaxOpenRequests = int(maxsends)
	pconf.Net.DialTimeout = connectTimeoutSecs * time.Second
	pconf.Net.ReadTimeout = connectTimeoutSecs * time.Second
	pconf.Net.WriteTimeout = connectTimeoutSecs * time.Second
	pconf.Net.KeepAlive = keepaliveSecs * time.Second

	pconf.Producer.Return.Errors = true
	pconf.Producer.Flush.Messages = maxFlushMsgs
	pconf.Producer.Flush.Frequency = maxFlushFreqSecs * time.Second

	asyncp, err := sarama.NewAsyncProducer(brokers, pconf)
	if err != nil {
		return nil, err
	}

	cconf := cluster.NewConfig()
	cconf.Version = pconf.Version
	cconf.Net = pconf.Net
	cconf.Consumer.Return.Errors = true

	kp := &KafkaManager{
		ap:           asyncp,
		topic:        topic,
		brokers:      brokers,
		consumerConf: cconf,
		mc:           mc,
		logger:       logger,
	}
	go kp.handlePErrors()
	return kp, nil
}

func (kp *KafkaManager) handlePErrors() {
	var kerr *sarama.ProducerError
	for {
		kerr = <-kp.ap.Errors()
		log.Printf("Kafka producer error: %v", kerr)
		kp.mc.KafkaProducerFailure()
	}
}

// PublishEvent publishes a build event to the configured Kafka topic
func (kp *KafkaManager) PublishEvent(event *lib.BuildEvent) error {
	id, err := gocql.ParseUUID(event.BuildId)
	if err != nil {
		return err
	}
	val, err := proto.Marshal(event)
	if err != nil {
		return fmt.Errorf("error marshaling protobuf: %v", err)
	}
	pmsg := &sarama.ProducerMessage{
		Topic: kp.topic,
		Key:   sarama.ByteEncoder(id.Bytes()), // Key is build ID to preserve event order (all events of a build go to the same partition)
		Value: sarama.ByteEncoder(val),
	}
	select { // don't block if Kafka is unavailable for some reason
	case kp.ap.Input() <- pmsg:
		return nil
	default:
		kp.mc.KafkaProducerFailure()
		return fmt.Errorf("could not publish Kafka message: channel full")
	}
}

// SubscribeToTopic listens to the configured topic, filters by build_id and writes
// the resulting messages to output. When the subscribed build is finished
// output is closed. done is a signal from the caller to abort the stream subscription
func (kp *KafkaManager) SubscribeToTopic(output chan<- *lib.BuildEvent, done <-chan struct{}, buildID gocql.UUID) error {
	// random group ID for each connection
	groupid, err := gocql.RandomUUID()
	if err != nil {
		return err
	}
	con, err := cluster.NewConsumer(kp.brokers, groupid.String(), []string{kp.topic}, kp.consumerConf)
	if err != nil {
		return err
	}
	handleConsumerErrors := func() {
		var err error
		for {
			err = <-con.Errors()
			if err == nil { // chan closed
				return
			}
			kp.mc.KafkaConsumerFailure()
			kp.logger.Printf("Kafka consumer error: %v", err)
		}
	}
	go handleConsumerErrors()
	go func() {
		defer close(output)
		defer con.Close()
		var err error
		var msg *sarama.ConsumerMessage
		var event *lib.BuildEvent
		input := con.Messages()
		for {
			select {
			case <-done:
				kp.logger.Printf("SubscribeToTopic: aborting")
				return
			default:
				break
			}
			msg = <-input
			if msg == nil {
				return
			}
			if bytes.Equal(msg.Key, []byte(buildID[:])) {
				event = &lib.BuildEvent{}
				err = proto.Unmarshal(msg.Value, event)
				if err != nil {
					kp.logger.Printf("%v: error unmarshaling event from Kafka stream: %v", buildID.String(), err)
					continue
				}
				output <- event
				if event.BuildFinished || event.EventError.IsError {
					return
				}
			}
		}
	}()
	return nil
}
<|endoftext|>


<commit_before>package route

import (
	"bytes"
	"errors"
	"fmt"
	"hash/adler32"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"path"
	"strconv"
	"strings"
	"sync"

	"github.com/coreos/go-etcd/etcd"
	"github.com/pachyderm/pfs/lib/etcache"
)

var ErrNoHosts = errors.New("pfs: no hosts found")

func HashResource(resource string) uint64 {
	return uint64(adler32.Checksum([]byte(resource)))
}

// Parse a string descriving a shard, the string looks like: "0-4"
func ParseShard(shardDesc string) (uint64, uint64, error) {
	s_m := strings.Split(shardDesc, "-")
	shard, err := strconv.ParseUint(s_m[0], 10, 64)
	if err != nil {
		return 0, 0, err
	}
	modulos, err := strconv.ParseUint(s_m[1], 10, 64)
	if err != nil {
		return 0, 0, err
	}
	return shard, modulos, nil
}

// Match returns true of a resource hashes to the given shard.
func Match(resource, shardDesc string) (bool, error) {
	shard, modulos, err := ParseShard(shardDesc)
	if err != nil {
		return false, err
	}
	return (HashResource(resource) % modulos) == shard, nil
}

func hashRequest(r *http.Request) uint64 {
	return HashResource(r.URL.Path)
}

func Route(r *http.Request, etcdKey string, modulos uint64) (io.ReadCloser, error) {
	bucket := hashRequest(r) % modulos
	shard := fmt.Sprint(bucket, "-", fmt.Sprint(modulos))

	_master, err := etcache.Get(path.Join(etcdKey, shard), false, false)
	if err != nil {
		return nil, err
	}
	master := _master.Node.Value

	httpClient := &http.Client{}
	// `Do` will complain if r.RequestURI is set so we unset it
	r.RequestURI = ""
	r.URL.Scheme = "http"
	r.URL.Host = strings.TrimPrefix(master, "http://")
	resp, err := httpClient.Do(r)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Failed request (%s) to %s.", resp.Status, r.URL.String())
	}
	return resp.Body, nil
}

func RouteHttp(w http.ResponseWriter, r *http.Request, etcdKey string, modulos uint64) {
	reader, err := Route(r, etcdKey, modulos)
	if err != nil {
		http.Error(w, err.Error(), 500)
		log.Print(err)
		return
	}
	_, err = io.Copy(w, reader)
	if err != nil {
		http.Error(w, err.Error(), 500)
		log.Print(err)
		return
	}
}

type multiReadCloser struct {
	readers []io.ReadCloser
}

func (mr *multiReadCloser) Read(p []byte) (n int, err error) {
	for len(mr.readers) > 0 {
		n, err = mr.readers[0].Read(p)
		if n > 0 || err != io.EOF {
			if err == io.EOF {
				// Don't return EOF yet. There may be more bytes
				// in the remaining readers.
				err = nil
			}
			return
		}
		err = mr.readers[0].Close()
		if err != nil {
			return
		}
		mr.readers = mr.readers[1:]
	}
	return 0, io.EOF
}

func (mr *multiReadCloser) Close() error {
	for len(mr.readers) > 0 {
		err := mr.readers[0].Close()
		if err != nil {
			return err
		}
		mr.readers = mr.readers[1:]
	}
	return nil
}

// MultiReadCloser returns a ReaderCloser that's the logical concatenation of
// the provided input readers. They're read sequentially.  Once all inputs have
// returned EOF, Read will return EOF. If any of the readers return a non-nil,
// non-EOF error, Read will return that error.  MultiReadCloser closes all of
// the input readers when it is closed. It also closes readers when they finish.
func MultiReadCloser(readers ...io.ReadCloser) io.ReadCloser {
	r := make([]io.ReadCloser, len(readers))
	copy(r, readers)
	return &multiReadCloser{r}
}

// Multicast enables the Ogre Magi to rapidly cast his spells, giving them
// greater potency.
// Multicast sends a request to every host it finds under a key and returns a
// ReadCloser for each one.
func Multicast(r *http.Request, etcdKey string) ([]*http.Response, error) {
	_endpoints, err := etcache.Get(etcdKey, false, true)
	if err != nil {
		return nil, err
	}
	endpoints := _endpoints.Node.Nodes
	if len(endpoints) == 0 {
		return nil, ErrNoHosts
	}

	// If the request has a body we need to store it in memory because it needs
	// to be sent to multiple endpoints and Reader (the type of r.Body) is
	// single use.
	var body []byte
	if r.ContentLength != 0 {
		body, err = ioutil.ReadAll(r.Body)
		if err != nil {
			return nil, err
		}
	}

	var resps []*http.Response
	errors := make(chan error, len(endpoints))
	var lock sync.Mutex
	var wg sync.WaitGroup
	wg.Add(len(endpoints))
	for _, node := range endpoints {
		go func(node *etcd.Node) {
			defer wg.Done()
			httpClient := &http.Client{}
			// First make a request, taking some values from the previous request.
			url := node.Value + r.URL.Path + "?" + r.URL.RawQuery
			req, err := http.NewRequest(r.Method, url,
				ioutil.NopCloser(bytes.NewReader(body)))
			if err != nil {
				errors <- err
				return
			}
			// Send the request
			resp, err := httpClient.Do(req)
			if err != nil {
				errors <- err
				return
			}
			if resp.StatusCode != 200 {
				errors <- fmt.Errorf("Failed request (%s) to %s.", resp.Status, r.URL.String())
				return
			}
			// Append the request to the response slice.
			lock.Lock()
			resps = append(resps, resp)
			lock.Unlock()
		}(node)
	}
	wg.Wait()
	close(errors)

	for err := range errors {
		if err != nil {
			return nil, err
		}
	}

	return resps, nil
}

type ForwardingPolicy int

const (
	// ReturnOne makes MulticastHttp return only the first response
	ReturnOne ForwardingPolicy = iota
	// ReturnAll makes MulticastHttp return all the responses
	ReturnAll ForwardingPolicy = iota
)

// MulticastHttp sends r to every host it finds under etcdKey, then prints the
// response to w based on
func MulticastHttp(w http.ResponseWriter, r *http.Request, etcdKey string, f ForwardingPolicy) {
	resps, err := Multicast(r, etcdKey)
	if err != nil {
		http.Error(w, err.Error(), 500)
		log.Print(err)
		return
	}
	var readers []io.ReadCloser
	for _, resp := range resps {
		readers = append(readers, resp.Body)
	}
	var reader io.ReadCloser
	switch f {
	case ReturnOne:
		reader = readers[0]
	case ReturnAll:
		reader = MultiReadCloser(readers...)
	default:
		http.Error(w, "Internal error.", 500)
		log.Print("Invalid ForwardingPolicy (programmer error)")
		return
	}
	defer reader.Close() //this line will close all of the readers

	_, err = io.Copy(w, reader)
	if err != nil {
		http.Error(w, err.Error(), 500)
		log.Print(err)
		return
	}
}
<commit_msg>Smarter concatenating of responses in lib/route.<commit_after>package route

import (
	"bytes"
	"errors"
	"fmt"
	"hash/adler32"
	"io"
	"io/ioutil"
	"log"
	"mime/multipart"
	"net/http"
	"path"
	"strconv"
	"strings"
	"sync"

	"github.com/coreos/go-etcd/etcd"
	"github.com/pachyderm/pfs/lib/etcache"
)

var ErrNoHosts = errors.New("pfs: no hosts found")

func HashResource(resource string) uint64 {
	return uint64(adler32.Checksum([]byte(resource)))
}

// Parse a string descriving a shard, the string looks like: "0-4"
func ParseShard(shardDesc string) (uint64, uint64, error) {
	s_m := strings.Split(shardDesc, "-")
	shard, err := strconv.ParseUint(s_m[0], 10, 64)
	if err != nil {
		return 0, 0, err
	}
	modulos, err := strconv.ParseUint(s_m[1], 10, 64)
	if err != nil {
		return 0, 0, err
	}
	return shard, modulos, nil
}

// Match returns true of a resource hashes to the given shard.
func Match(resource, shardDesc string) (bool, error) {
	shard, modulos, err := ParseShard(shardDesc)
	if err != nil {
		return false, err
	}
	return (HashResource(resource) % modulos) == shard, nil
}

func hashRequest(r *http.Request) uint64 {
	return HashResource(r.URL.Path)
}

func Route(r *http.Request, etcdKey string, modulos uint64) (io.ReadCloser, error) {
	bucket := hashRequest(r) % modulos
	shard := fmt.Sprint(bucket, "-", fmt.Sprint(modulos))

	_master, err := etcache.Get(path.Join(etcdKey, shard), false, false)
	if err != nil {
		return nil, err
	}
	master := _master.Node.Value

	httpClient := &http.Client{}
	// `Do` will complain if r.RequestURI is set so we unset it
	r.RequestURI = ""
	r.URL.Scheme = "http"
	r.URL.Host = strings.TrimPrefix(master, "http://")
	resp, err := httpClient.Do(r)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("Failed request (%s) to %s.", resp.Status, r.URL.String())
	}
	return resp.Body, nil
}

func RouteHttp(w http.ResponseWriter, r *http.Request, etcdKey string, modulos uint64) {
	reader, err := Route(r, etcdKey, modulos)
	if err != nil {
		http.Error(w, err.Error(), 500)
		log.Print(err)
		return
	}
	_, err = io.Copy(w, reader)
	if err != nil {
		http.Error(w, err.Error(), 500)
		log.Print(err)
		return
	}
}

type multiReadCloser struct {
	readers []io.ReadCloser
}

func (mr *multiReadCloser) Read(p []byte) (n int, err error) {
	for len(mr.readers) > 0 {
		n, err = mr.readers[0].Read(p)
		if n > 0 || err != io.EOF {
			if err == io.EOF {
				// Don't return EOF yet. There may be more bytes
				// in the remaining readers.
				err = nil
			}
			return
		}
		err = mr.readers[0].Close()
		if err != nil {
			return
		}
		mr.readers = mr.readers[1:]
	}
	return 0, io.EOF
}

func (mr *multiReadCloser) Close() error {
	for len(mr.readers) > 0 {
		err := mr.readers[0].Close()
		if err != nil {
			return err
		}
		mr.readers = mr.readers[1:]
	}
	return nil
}

// MultiReadCloser returns a ReaderCloser that's the logical concatenation of
// the provided input readers. They're read sequentially.  Once all inputs have
// returned EOF, Read will return EOF. If any of the readers return a non-nil,
// non-EOF error, Read will return that error.  MultiReadCloser closes all of
// the input readers when it is closed. It also closes readers when they finish.
func MultiReadCloser(readers ...io.ReadCloser) io.ReadCloser {
	r := make([]io.ReadCloser, len(readers))
	copy(r, readers)
	return &multiReadCloser{r}
}

// Multicast enables the Ogre Magi to rapidly cast his spells, giving them
// greater potency.
// Multicast sends a request to every host it finds under a key and returns a
// ReadCloser for each one.
func Multicast(r *http.Request, etcdKey string) ([]*http.Response, error) {
	_endpoints, err := etcache.Get(etcdKey, false, true)
	if err != nil {
		return nil, err
	}
	endpoints := _endpoints.Node.Nodes
	if len(endpoints) == 0 {
		return nil, ErrNoHosts
	}

	// If the request has a body we need to store it in memory because it needs
	// to be sent to multiple endpoints and Reader (the type of r.Body) is
	// single use.
	var body []byte
	if r.ContentLength != 0 {
		body, err = ioutil.ReadAll(r.Body)
		if err != nil {
			return nil, err
		}
	}

	var resps []*http.Response
	errors := make(chan error, len(endpoints))
	var lock sync.Mutex
	var wg sync.WaitGroup
	wg.Add(len(endpoints))
	for _, node := range endpoints {
		go func(node *etcd.Node) {
			defer wg.Done()
			httpClient := &http.Client{}
			// First make a request, taking some values from the previous request.
			url := node.Value + r.URL.Path + "?" + r.URL.RawQuery
			req, err := http.NewRequest(r.Method, url,
				ioutil.NopCloser(bytes.NewReader(body)))
			if err != nil {
				errors <- err
				return
			}
			// Send the request
			resp, err := httpClient.Do(req)
			if err != nil {
				errors <- err
				return
			}
			if resp.StatusCode != 200 {
				errors <- fmt.Errorf("Failed request (%s) to %s.", resp.Status, r.URL.String())
				return
			}
			// Append the request to the response slice.
			lock.Lock()
			resps = append(resps, resp)
			lock.Unlock()
		}(node)
	}
	wg.Wait()
	close(errors)

	for err := range errors {
		if err != nil {
			return nil, err
		}
	}

	return resps, nil
}

type Return int

const (
	// ReturnFirst returns only the first response
	ReturnOne Return = iota
	// ReturnAll returns all the responses
	ReturnAll Return = iota
)

// MulticastHttp sends r to every host it finds under etcdKey, then prints the
// response to w based on
func MulticastHttp(w http.ResponseWriter, r *http.Request, etcdKey string, ret Return) {
	// resps is guaranteed to be nonempty
	resps, err := Multicast(r, etcdKey)
	if err != nil {
		http.Error(w, err.Error(), 500)
		log.Print(err)
		return
	}
	defer func() {
		for _, r := range resps {
			r.Body.Close()
		}
	}()
	switch ret {
	case ReturnOne:
		_, err = io.Copy(w, resps[0].Body)
		if err != nil {
			http.Error(w, err.Error(), 500)
			log.Print(err)
			return
		}
		return
	case ReturnAll:
		// We use the existence of "Boundary" to figure out how to concatenate
		// the responses
		if resps[0].Header.Get("Boundary") == "" {
			// plain text
			for _, resp := range resps {
				_, err = io.Copy(w, resp.Body)
				if err != nil {
					http.Error(w, err.Error(), 500)
					log.Print(err)
					return
				}
				resp.Body.Close()
			}
		} else {
			// multipart
			writer := multipart.NewWriter(w)
			defer writer.Close()
			w.Header().Add("Boundary", writer.Boundary())
			for _, resp := range resps {
				reader := multipart.NewReader(resp.Body, resp.Header.Get("Boundary"))
				for p, err := reader.NextPart(); err == nil; p, err = reader.NextPart() {
					f, err := writer.CreateFormFile(p.FormName(), p.FileName())
					if err != nil {
						http.Error(w, err.Error(), 500)
						log.Print(err)
						return
					}
					_, err = io.Copy(f, p)
					if err != nil {
						http.Error(w, err.Error(), 500)
						log.Print(err)
						return
					}
				}
				resp.Body.Close()
			}
		}
	}
}
<|endoftext|>


<commit_before>package template

import (
	"errors"
	"html/template"
	"strings"
)

var funcMap = template.FuncMap{
	"javascript_include_tag": JavascriptIncludeTag,
	"stylesheet_link_tag":    StylesheetLinkTag,
	"favicon_link_tag":       FaviconLinkTag,
	"tag_opts":               newTagOpts,
}

/*
 * FuncMap adds functions to the template
 *
 * javascript_include_tag
 * Adds a script tag.
 * Arguments:
 * name
 * ( tag_opts )
 *
 * stylesheet_link_tag
 * Adds a script tag.
 * Arguments:
 * name
 * ( tag_opts )
 *
 * favicon_link_tag
 * Adds a link rel="icon" tag.
 * Arguments:
 * name
 * ( tag_opts )
 *
 * tag_opts
 * Adds attributes to a tag.
 * Arguments:
 * space separated tuples
 * e.g. "rel" "icon" "type" "image/png"
 * Returns an error stopping the template parsing if an odd number of
 * arguments are given
 *
 * It's important to use parens separated by spaces around the tag_opts
 * when used to pass arguments to the various tags.
 * e.g. javascript_include_tag "bar" ( tag_opts "charset" "utf-8" )
 */
func FuncMap(t *template.Template) {
	t.Funcs(funcMap)
}

/* TagOpts are attribute options to insert into a tag */
type TagOpts map[string]string

/* String converts the TagOpts map to an attribute string */
func (t TagOpts) String() string {
	var to string

	for k, v := range t {
		to += k + `="` + v + `" `
	}

	return to
}

/* newTagOpts creates tag attributes */
func newTagOpts(opts ...string) (TagOpts, error) {
	var to TagOpts

	if len(opts) == 0 {
		return to, nil
	} else if len(opts)%2 == 1 {
		return to, errors.New("expects an even number of parameters")
	} else {
		to = make(TagOpts)
	}

	for i := 0; i < len(opts); i += 2 {
		to[opts[i]] = opts[i+1]
	}

	return to, nil
}

func getTagOpt(opts ...TagOpts) TagOpts {
	var o TagOpts
	if len(opts) == 0 {
		o = make(TagOpts)
	} else {
		o = opts[0]
	}

	return o
}

/* tag creates an open tag */
func tag(t string, opts ...TagOpts) template.HTML {
	tag := "<" + t + " "
	if len(opts) > 0 {
		tag += opts[0].String()
	}
	tag = strings.TrimSpace(tag)
	tag += ">"

	return template.HTML(tag)
}

/* JavascriptIncludeTag creates a script src tag */
func JavascriptIncludeTag(name string, opts ...TagOpts) template.HTML {
	o := getTagOpt(opts...)

	o["src"] = name

	return tag("script", o) + "</script>"
}

func linkTag(name string, opts ...TagOpts) template.HTML {
	o := getTagOpt(opts...)
	o["href"] = name

	return tag("link", o)
}

/* StylesheetLinkTag creates a link rel="stylesheet" tag */
func StylesheetLinkTag(name string, opts ...TagOpts) template.HTML {
	o := getTagOpt(opts...)

	o["rel"] = "stylesheet"

	return linkTag(name, o)
}

/* FaviconLinkTag creates a link rel="shortcut icon" tag */
func FaviconLinkTag(name string, opts ...TagOpts) template.HTML {
	o := getTagOpt(opts...)

	if o["rel"] == "" {
		o["rel"] = "shortcut icon"
	}
	if o["type"] == "" {
		o["type"] = "image/vnd.microsoft.icon"
	}

	return linkTag(name, o)
}
<commit_msg>Fix assignment to TagOpts after call to newTagOpts with nil<commit_after>package template

import (
	"errors"
	"html/template"
	"strings"
)

var funcMap = template.FuncMap{
	"javascript_include_tag": JavascriptIncludeTag,
	"stylesheet_link_tag":    StylesheetLinkTag,
	"favicon_link_tag":       FaviconLinkTag,
	"tag_opts":               newTagOpts,
}

/*
 * FuncMap adds functions to the template
 *
 * javascript_include_tag
 * Adds a script tag.
 * Arguments:
 * name
 * ( tag_opts )
 *
 * stylesheet_link_tag
 * Adds a script tag.
 * Arguments:
 * name
 * ( tag_opts )
 *
 * favicon_link_tag
 * Adds a link rel="icon" tag.
 * Arguments:
 * name
 * ( tag_opts )
 *
 * tag_opts
 * Adds attributes to a tag.
 * Arguments:
 * space separated tuples
 * e.g. "rel" "icon" "type" "image/png"
 * Returns an error stopping the template parsing if an odd number of
 * arguments are given
 *
 * It's important to use parens separated by spaces around the tag_opts
 * when used to pass arguments to the various tags.
 * e.g. javascript_include_tag "bar" ( tag_opts "charset" "utf-8" )
 */
func FuncMap(t *template.Template) {
	t.Funcs(funcMap)
}

/* TagOpts are attribute options to insert into a tag */
type TagOpts map[string]string

/* String converts the TagOpts map to an attribute string */
func (t TagOpts) String() string {
	var to string

	for k, v := range t {
		to += k + `="` + v + `" `
	}

	return to
}

/* newTagOpts creates tag attributes */
func newTagOpts(opts ...string) (TagOpts, error) {
	var to TagOpts

	if len(opts) == 0 {
		return make(TagOpts), nil
	} else if len(opts)%2 == 1 {
		return to, errors.New("expects an even number of parameters")
	} else {
		to = make(TagOpts)
	}

	for i := 0; i < len(opts); i += 2 {
		to[opts[i]] = opts[i+1]
	}

	return to, nil
}

func getTagOpt(opts ...TagOpts) TagOpts {
	var o TagOpts
	if len(opts) == 0 {
		o = make(TagOpts)
	} else {
		o = opts[0]
	}

	return o
}

/* tag creates an open tag */
func tag(t string, opts ...TagOpts) template.HTML {
	tag := "<" + t + " "
	if len(opts) > 0 {
		tag += opts[0].String()
	}
	tag = strings.TrimSpace(tag)
	tag += ">"

	return template.HTML(tag)
}

/* JavascriptIncludeTag creates a script src tag */
func JavascriptIncludeTag(name string, opts ...TagOpts) template.HTML {
	o := getTagOpt(opts...)

	o["src"] = name

	return tag("script", o) + "</script>"
}

func linkTag(name string, opts ...TagOpts) template.HTML {
	o := getTagOpt(opts...)
	o["href"] = name

	return tag("link", o)
}

/* StylesheetLinkTag creates a link rel="stylesheet" tag */
func StylesheetLinkTag(name string, opts ...TagOpts) template.HTML {
	o := getTagOpt(opts...)

	o["rel"] = "stylesheet"

	return linkTag(name, o)
}

/* FaviconLinkTag creates a link rel="shortcut icon" tag */
func FaviconLinkTag(name string, opts ...TagOpts) template.HTML {
	o := getTagOpt(opts...)

	if o["rel"] == "" {
		o["rel"] = "shortcut icon"
	}
	if o["type"] == "" {
		o["type"] = "image/vnd.microsoft.icon"
	}

	return linkTag(name, o)
}
<|endoftext|>


<commit_before>// Package pastebin is a simple modern and powerful pastebin service
package pastebin

import (
	"crypto/sha1"
	"database/sql"
	"encoding/base64"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"html"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"time"

	duration "github.com/channelmeter/iso8601duration"
	// uniuri is used for easy random string generation
	"github.com/dchest/uniuri"
	// pygments is used for syntax highlighting
	"github.com/ewhal/pygments"
	// mysql driver
	_ "github.com/go-sql-driver/mysql"
	// mux is used for url routing
	"github.com/gorilla/mux"
)

const (
	// ADDRESS that pastebin will return links for
	ADDRESS = "http://localhost:9900"
	// LENGTH of paste id
	LENGTH = 6
	// PORT that pastebin will listen on
	PORT = ":9900"
	// USERNAME for database
	USERNAME = ""
	// PASS database password
	PASS = ""
	// NAME database name
	NAME = ""
	// DATABASE connection String
	DATABASE = USERNAME + ":" + PASS + "@/" + NAME + "?charset=utf8"
)

// Template pages
var templates = template.Must(template.ParseFiles("assets/paste.html", "assets/index.html", "assets/clone.html"))
var syntax, _ = ioutil.ReadFile("assets/syntax.html")

// Response API struct
type Response struct {
	ID     string `json:"id"`
	TITLE  string `json:"title"`
	SHA1   string `json:"sha1"`
	URL    string `json:"url"`
	SIZE   int    `json:"size"`
	DELKEY string `json:"delkey"`
}

// Page generation struct
type Page struct {
	Title    string
	Body     []byte
	Raw      string
	Home     string
	Download string
	Clone    string
}

// check error handling function
func Check(err error) {
	if err != nil {
		log.Println(err)
	}
}

// GenerateName uses uniuri to generate a random string that isn't in the
// database
func GenerateName() string {
	// use uniuri to generate random string
	id := uniuri.NewLen(LENGTH)

	db, err := sql.Open("mysql", DATABASE)
	Check(err)
	defer db.Close()
	// query database if id exists and if it does call generateName again
	query, err := db.Query("select id from pastebin where id=?", id)
	if err != sql.ErrNoRows {
		for query.Next() {
			GenerateName()
		}
	}

	return id

}

// Sha1 hashes paste into a sha1 hash
func Sha1(paste string) string {
	hasher := sha1.New()

	hasher.Write([]byte(paste))
	sha := base64.URLEncoding.EncodeToString(hasher.Sum(nil))
	return sha
}

// DurationFromExpiry takes the expiry in string format and returns the duration
// that the paste will exist for
func DurationFromExpiry(expiry string) time.Duration {
	if expiry == "" {
		expiry = "P20Y"
	}
	dura, err := duration.FromString(expiry) // dura is time.Duration type
	Check(err)

	duration := dura.ToDuration()

	return duration
}

// Save function handles the saving of each paste.
// raw string is the raw paste input
// lang string is the user specified language for syntax highlighting
// title string user customized title
// expiry string duration that the paste will exist for
// Returns Response struct
func Save(raw string, lang string, title string, expiry string) Response {

	db, err := sql.Open("mysql", DATABASE)
	Check(err)
	defer db.Close()

	// hash paste data and query database to see if paste exists
	sha := Sha1(raw)
	query, err := db.Query("select id, title, hash, data, delkey from pastebin where hash=?", sha)

	if err != sql.ErrNoRows {
		for query.Next() {
			var id, title, hash, paste, delkey string
			err := query.Scan(&id, &title, &hash, &paste, &delkey)
			Check(err)
			url := ADDRESS + "/p/" + id
			return Response{id, title, hash, url, len(paste), delkey}
		}
	}
	id := GenerateName()
	url := ADDRESS + "/p/" + id
	if lang != "" {
		url += "/" + lang
	}

	const timeFormat = "2006-01-02 15:04:05"
	expiryTime := time.Now().Add(DurationFromExpiry(expiry)).Format(timeFormat)

	delKey := uniuri.NewLen(40)
	dataEscaped := html.EscapeString(raw)

	stmt, err := db.Prepare("INSERT INTO pastebin(id, title, hash, data, delkey, expiry) values(?,?,?,?,?,?)")
	Check(err)
	if title == "" {
		title = id
	}
	_, err = stmt.Exec(id, html.EscapeString(title), sha, dataEscaped, delKey, expiryTime)
	Check(err)

	return Response{id, title, sha, url, len(dataEscaped), delKey}
}

// DelHandler checks to see if delkey and pasteid exist in the database.
// if both exist and are correct the paste will be removed.
func DelHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	id := vars["pasteId"]
	delkey := vars["delKey"]

	db, err := sql.Open("mysql", DATABASE)
	Check(err)
	defer db.Close()

	stmt, err := db.Prepare("delete from pastebin where delkey=? and id=?")
	Check(err)

	res, err := stmt.Exec(html.EscapeString(delkey), html.EscapeString(id))
	Check(err)

	_, err = res.RowsAffected()
	if err != sql.ErrNoRows {
		io.WriteString(w, id+" deleted")
	}
}

// SaveHandler Handles saving pastes and outputing responses
func SaveHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	output := vars["output"]
	switch r.Method {
	case "POST":
		paste := r.FormValue("p")
		lang := r.FormValue("lang")
		title := r.FormValue("title")
		expiry := r.FormValue("expiry")
		if paste == "" {
			http.Error(w, "Empty paste", 500)
			return
		}
		b := Save(paste, lang, title, expiry)

		switch output {
		case "json":
			w.Header().Set("Content-Type", "application/json")
			err := json.NewEncoder(w).Encode(b)
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}

		case "xml":
			x, err := xml.MarshalIndent(b, "", "  ")
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}

			w.Header().Set("Content-Type", "application/xml")
			w.Write(x)

		case "html":
			w.Header().Set("Content-Type", "text/html")
			io.WriteString(w, "
URL: "+b.URL+"
")
			io.WriteString(w, "
Delete Key: "+b.DELKEY+"
")

		case "redirect":
			http.Redirect(w, r, b.URL, 301)

		default:
			w.Header().Set("Content-Type", "text/plain; charset=UTF-8; imeanit=yes")
			io.WriteString(w, b.URL+"\n")
			io.WriteString(w, "delete key: "+b.DELKEY+"\n")
		}
	}

}

// Highlight uses user specified input to call pygments library to highlight the
// paste
func Highlight(s string, lang string) (string, error) {

	highlight, err := pygments.Highlight(html.UnescapeString(s), html.EscapeString(lang), "html", "style=autumn,linenos=True, lineanchors=True,anchorlinenos=True,noclasses=True,", "utf-8")
	if err != nil {
		return "", err
	}
	return highlight, nil

}

// GetPaste takes pasteid and language
// queries the database and returns paste data
func GetPaste(paste string, lang string) (string, string) {
	param1 := html.EscapeString(paste)
	db, err := sql.Open("mysql", DATABASE)
	Check(err)
	defer db.Close()
	var title, s string
	var expiry string
	err = db.QueryRow("select title, data, expiry from pastebin where id=?", param1).Scan(&title, &s, &expiry)
	Check(err)
	if time.Now().Format("2006-01-02 15:04:05") > expiry {
		stmt, err := db.Prepare("delete from pastebin where id=?")
		Check(err)
		_, err = stmt.Exec(param1)
		Check(err)
		return "Error invalid paste", ""
	}

	if err == sql.ErrNoRows {
		return "Error invalid paste", ""
	}
	if lang != "" {
		high, err := Highlight(s, lang)
		Check(err)
		return high, html.UnescapeString(title)
	}
	return html.UnescapeString(s), html.UnescapeString(title)
}

// PasteHandler handles the generation of paste pages with the links
func PasteHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	lang := vars["lang"]

	s, title := GetPaste(paste, lang)

	// button links
	link := ADDRESS + "/raw/" + paste
	download := ADDRESS + "/download/" + paste
	clone := ADDRESS + "/clone/" + paste
	// Page struct
	p := &Page{
		Title:    title,
		Body:     []byte(s),
		Raw:      link,
		Home:     ADDRESS,
		Download: download,
		Clone:    clone,
	}
	if lang == "" {

		err := templates.ExecuteTemplate(w, "paste.html", p)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}

	} else {
		fmt.Fprintf(w, string(syntax), p.Title, p.Title, s, p.Home, p.Download, p.Raw, p.Clone)

	}
}

// CloneHandler handles generating the clone pages
func CloneHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]

	s, title := GetPaste(paste, "")

	// Page links
	link := ADDRESS + "/raw/" + paste
	download := ADDRESS + "/download/" + paste
	clone := ADDRESS + "/clone/" + paste

	// Clone page struct
	p := &Page{
		Title:    title,
		Body:     []byte(s),
		Raw:      link,
		Home:     ADDRESS,
		Download: download,
		Clone:    clone,
	}
	err := templates.ExecuteTemplate(w, "clone.html", p)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}

}

// DownloadHandler forces downloads of selected pastes
func DownloadHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	s, _ := GetPaste(paste, "")

	// Set header to an attachment so browser will automatically download it
	w.Header().Set("Content-Disposition", "attachment; filename="+paste)
	w.Header().Set("Content-Type", r.Header.Get("Content-Type"))
	io.WriteString(w, s)

}

// RawHandler displays the pastes in text/plain format
func RawHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	s, _ := GetPaste(paste, "")

	w.Header().Set("Content-Type", "text/plain; charset=UTF-8; imeanit=yes")
	// simply write string to browser
	io.WriteString(w, s)

}

// RootHandler handles generating the root page
func RootHandler(w http.ResponseWriter, r *http.Request) {
	err := templates.ExecuteTemplate(w, "index.html", &Page{})
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func main() {
	router := mux.NewRouter()
	router.HandleFunc("/p/{pasteId}", PasteHandler).Methods("GET")
	router.HandleFunc("/raw/{pasteId}", RawHandler).Methods("GET")
	router.HandleFunc("/p/{pasteId}/{lang}", PasteHandler).Methods("GET")
	router.HandleFunc("/clone/{pasteId}", CloneHandler).Methods("GET")
	router.HandleFunc("/download/{pasteId}", DownloadHandler).Methods("GET")
	router.HandleFunc("/p", SaveHandler).Methods("POST")
	router.HandleFunc("/p/{output}", SaveHandler).Methods("POST")
	router.HandleFunc("/p/{pasteId}/{delKey}", DelHandler).Methods("DELETE")
	router.HandleFunc("/", RootHandler)
	err := http.ListenAndServe(PORT, router)
	if err != nil {
		log.Fatal(err)
	}

}
<commit_msg>Rename package to main<commit_after>// Package pastebin is a simple modern and powerful pastebin service
package main

import (
	"crypto/sha1"
	"database/sql"
	"encoding/base64"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"html"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"time"

	duration "github.com/channelmeter/iso8601duration"
	// uniuri is used for easy random string generation
	"github.com/dchest/uniuri"
	// pygments is used for syntax highlighting
	"github.com/ewhal/pygments"
	// mysql driver
	_ "github.com/go-sql-driver/mysql"
	// mux is used for url routing
	"github.com/gorilla/mux"
)

const (
	// ADDRESS that pastebin will return links for
	ADDRESS = "http://localhost:9900"
	// LENGTH of paste id
	LENGTH = 6
	// PORT that pastebin will listen on
	PORT = ":9900"
	// USERNAME for database
	USERNAME = ""
	// PASS database password
	PASS = ""
	// NAME database name
	NAME = ""
	// DATABASE connection String
	DATABASE = USERNAME + ":" + PASS + "@/" + NAME + "?charset=utf8"
)

// Template pages
var templates = template.Must(template.ParseFiles("assets/paste.html", "assets/index.html", "assets/clone.html"))
var syntax, _ = ioutil.ReadFile("assets/syntax.html")

// Response API struct
type Response struct {
	ID     string `json:"id"`
	TITLE  string `json:"title"`
	SHA1   string `json:"sha1"`
	URL    string `json:"url"`
	SIZE   int    `json:"size"`
	DELKEY string `json:"delkey"`
}

// Page generation struct
type Page struct {
	Title    string
	Body     []byte
	Raw      string
	Home     string
	Download string
	Clone    string
}

// check error handling function
func Check(err error) {
	if err != nil {
		log.Println(err)
	}
}

// GenerateName uses uniuri to generate a random string that isn't in the
// database
func GenerateName() string {
	// use uniuri to generate random string
	id := uniuri.NewLen(LENGTH)

	db, err := sql.Open("mysql", DATABASE)
	Check(err)
	defer db.Close()
	// query database if id exists and if it does call generateName again
	query, err := db.Query("select id from pastebin where id=?", id)
	if err != sql.ErrNoRows {
		for query.Next() {
			GenerateName()
		}
	}

	return id

}

// Sha1 hashes paste into a sha1 hash
func Sha1(paste string) string {
	hasher := sha1.New()

	hasher.Write([]byte(paste))
	sha := base64.URLEncoding.EncodeToString(hasher.Sum(nil))
	return sha
}

// DurationFromExpiry takes the expiry in string format and returns the duration
// that the paste will exist for
func DurationFromExpiry(expiry string) time.Duration {
	if expiry == "" {
		expiry = "P20Y"
	}
	dura, err := duration.FromString(expiry) // dura is time.Duration type
	Check(err)

	duration := dura.ToDuration()

	return duration
}

// Save function handles the saving of each paste.
// raw string is the raw paste input
// lang string is the user specified language for syntax highlighting
// title string user customized title
// expiry string duration that the paste will exist for
// Returns Response struct
func Save(raw string, lang string, title string, expiry string) Response {

	db, err := sql.Open("mysql", DATABASE)
	Check(err)
	defer db.Close()

	// hash paste data and query database to see if paste exists
	sha := Sha1(raw)
	query, err := db.Query("select id, title, hash, data, delkey from pastebin where hash=?", sha)

	if err != sql.ErrNoRows {
		for query.Next() {
			var id, title, hash, paste, delkey string
			err := query.Scan(&id, &title, &hash, &paste, &delkey)
			Check(err)
			url := ADDRESS + "/p/" + id
			return Response{id, title, hash, url, len(paste), delkey}
		}
	}
	id := GenerateName()
	url := ADDRESS + "/p/" + id
	if lang != "" {
		url += "/" + lang
	}

	const timeFormat = "2006-01-02 15:04:05"
	expiryTime := time.Now().Add(DurationFromExpiry(expiry)).Format(timeFormat)

	delKey := uniuri.NewLen(40)
	dataEscaped := html.EscapeString(raw)

	stmt, err := db.Prepare("INSERT INTO pastebin(id, title, hash, data, delkey, expiry) values(?,?,?,?,?,?)")
	Check(err)
	if title == "" {
		title = id
	}
	_, err = stmt.Exec(id, html.EscapeString(title), sha, dataEscaped, delKey, expiryTime)
	Check(err)

	return Response{id, title, sha, url, len(dataEscaped), delKey}
}

// DelHandler checks to see if delkey and pasteid exist in the database.
// if both exist and are correct the paste will be removed.
func DelHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	id := vars["pasteId"]
	delkey := vars["delKey"]

	db, err := sql.Open("mysql", DATABASE)
	Check(err)
	defer db.Close()

	stmt, err := db.Prepare("delete from pastebin where delkey=? and id=?")
	Check(err)

	res, err := stmt.Exec(html.EscapeString(delkey), html.EscapeString(id))
	Check(err)

	_, err = res.RowsAffected()
	if err != sql.ErrNoRows {
		io.WriteString(w, id+" deleted")
	}
}

// SaveHandler Handles saving pastes and outputing responses
func SaveHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	output := vars["output"]
	switch r.Method {
	case "POST":
		paste := r.FormValue("p")
		lang := r.FormValue("lang")
		title := r.FormValue("title")
		expiry := r.FormValue("expiry")
		if paste == "" {
			http.Error(w, "Empty paste", 500)
			return
		}
		b := Save(paste, lang, title, expiry)

		switch output {
		case "json":
			w.Header().Set("Content-Type", "application/json")
			err := json.NewEncoder(w).Encode(b)
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}

		case "xml":
			x, err := xml.MarshalIndent(b, "", "  ")
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}

			w.Header().Set("Content-Type", "application/xml")
			w.Write(x)

		case "html":
			w.Header().Set("Content-Type", "text/html")
			io.WriteString(w, "
URL: "+b.URL+"
")
			io.WriteString(w, "
Delete Key: "+b.DELKEY+"
")

		case "redirect":
			http.Redirect(w, r, b.URL, 301)

		default:
			w.Header().Set("Content-Type", "text/plain; charset=UTF-8; imeanit=yes")
			io.WriteString(w, b.URL+"\n")
			io.WriteString(w, "delete key: "+b.DELKEY+"\n")
		}
	}

}

// Highlight uses user specified input to call pygments library to highlight the
// paste
func Highlight(s string, lang string) (string, error) {

	highlight, err := pygments.Highlight(html.UnescapeString(s), html.EscapeString(lang), "html", "style=autumn,linenos=True, lineanchors=True,anchorlinenos=True,noclasses=True,", "utf-8")
	if err != nil {
		return "", err
	}
	return highlight, nil

}

// GetPaste takes pasteid and language
// queries the database and returns paste data
func GetPaste(paste string, lang string) (string, string) {
	param1 := html.EscapeString(paste)
	db, err := sql.Open("mysql", DATABASE)
	Check(err)
	defer db.Close()
	var title, s string
	var expiry string
	err = db.QueryRow("select title, data, expiry from pastebin where id=?", param1).Scan(&title, &s, &expiry)
	Check(err)
	if time.Now().Format("2006-01-02 15:04:05") > expiry {
		stmt, err := db.Prepare("delete from pastebin where id=?")
		Check(err)
		_, err = stmt.Exec(param1)
		Check(err)
		return "Error invalid paste", ""
	}

	if err == sql.ErrNoRows {
		return "Error invalid paste", ""
	}
	if lang != "" {
		high, err := Highlight(s, lang)
		Check(err)
		return high, html.UnescapeString(title)
	}
	return html.UnescapeString(s), html.UnescapeString(title)
}

// PasteHandler handles the generation of paste pages with the links
func PasteHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	lang := vars["lang"]

	s, title := GetPaste(paste, lang)

	// button links
	link := ADDRESS + "/raw/" + paste
	download := ADDRESS + "/download/" + paste
	clone := ADDRESS + "/clone/" + paste
	// Page struct
	p := &Page{
		Title:    title,
		Body:     []byte(s),
		Raw:      link,
		Home:     ADDRESS,
		Download: download,
		Clone:    clone,
	}
	if lang == "" {

		err := templates.ExecuteTemplate(w, "paste.html", p)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}

	} else {
		fmt.Fprintf(w, string(syntax), p.Title, p.Title, s, p.Home, p.Download, p.Raw, p.Clone)

	}
}

// CloneHandler handles generating the clone pages
func CloneHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]

	s, title := GetPaste(paste, "")

	// Page links
	link := ADDRESS + "/raw/" + paste
	download := ADDRESS + "/download/" + paste
	clone := ADDRESS + "/clone/" + paste

	// Clone page struct
	p := &Page{
		Title:    title,
		Body:     []byte(s),
		Raw:      link,
		Home:     ADDRESS,
		Download: download,
		Clone:    clone,
	}
	err := templates.ExecuteTemplate(w, "clone.html", p)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}

}

// DownloadHandler forces downloads of selected pastes
func DownloadHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	s, _ := GetPaste(paste, "")

	// Set header to an attachment so browser will automatically download it
	w.Header().Set("Content-Disposition", "attachment; filename="+paste)
	w.Header().Set("Content-Type", r.Header.Get("Content-Type"))
	io.WriteString(w, s)

}

// RawHandler displays the pastes in text/plain format
func RawHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	s, _ := GetPaste(paste, "")

	w.Header().Set("Content-Type", "text/plain; charset=UTF-8; imeanit=yes")
	// simply write string to browser
	io.WriteString(w, s)

}

// RootHandler handles generating the root page
func RootHandler(w http.ResponseWriter, r *http.Request) {
	err := templates.ExecuteTemplate(w, "index.html", &Page{})
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func main() {
	router := mux.NewRouter()
	router.HandleFunc("/p/{pasteId}", PasteHandler).Methods("GET")
	router.HandleFunc("/raw/{pasteId}", RawHandler).Methods("GET")
	router.HandleFunc("/p/{pasteId}/{lang}", PasteHandler).Methods("GET")
	router.HandleFunc("/clone/{pasteId}", CloneHandler).Methods("GET")
	router.HandleFunc("/download/{pasteId}", DownloadHandler).Methods("GET")
	router.HandleFunc("/p", SaveHandler).Methods("POST")
	router.HandleFunc("/p/{output}", SaveHandler).Methods("POST")
	router.HandleFunc("/p/{pasteId}/{delKey}", DelHandler).Methods("DELETE")
	router.HandleFunc("/", RootHandler)
	err := http.ListenAndServe(PORT, router)
	if err != nil {
		log.Fatal(err)
	}

}
<|endoftext|>


<commit_before>// +build windows

package ole

import "testing"

func wrapCOMExecute(t *testing.T, callback func(*testing.T)) {
	defer func() {
		if r := recover(); r != nil {
			t.Error(r)
		}
	}()

	err := CoInitialize(0)
	if err != nil {
		t.Fatal(err)
	}
	defer CoUninitialize()

	callback(t)
}

func wrapDispatch(t *testing.T, ClassID, UnknownInterfaceID, DispatchInterfaceID *GUID, callback func(*testing.T, *IUnknown, *IDispatch)) {
	var unknown *IUnknown
	var dispatch *IDispatch
	var err error

	unknown, err = CreateInstance(ClassID, UnknownInterfaceID)
	if err != nil {
		t.Error(err)
		return
	}
	defer unknown.Release()

	dispatch, err = unknown.QueryInterface(DispatchInterfaceID)
	if err != nil {
		t.Error(err)
		return
	}
	defer dispatch.Release()

	callback(t, unknown, dispatch)
}

func wrapGoOLETestCOMServer(t *testing.T, callback func(*testing.T, *IUnknown, *IDispatch)) {
	wrapCOMExecute(t, func(t *testing.T) {
		wrapDispatch(t, CLSID_COMEchoTestObject, IID_IUnknown, IID_ICOMEchoTestObject, callback)
	})
}

func TestIDispatch_goolecomserver_echostring(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoString"
		expected := "Test String"
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		variant.Clear()
		actual, passed := variant.Value().(string)
		if !passed {
			t.Errorf("%s() did not convert to %s, variant is %s with %v value", method, "string", variant.VT, variant.Val)
		}
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, actual)
		}
	})
}

func TestIDispatch_goolecomserver_echoint8(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoInt8"
		expected := int8(1)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		variant.Clear()
		actual, passed := variant.Value().(int8)
		if !passed {
			t.Errorf("%s() did not convert to %s, variant is %s with %v value", method, "int8", variant.VT, variant.Val)
		}
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, actual)
		}
	})
}

func TestIDispatch_goolecomserver_echouint8(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoUInt8"
		expected := uint8(1)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		variant.Clear()
		actual, passed := variant.Value().(uint8)
		if !passed {
			t.Errorf("%s() did not convert to %s, variant is %s with %v value", method, "uint8", variant.VT, variant.Val)
		}
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, actual)
		}
	})
}

func TestIDispatch_goolecomserver_echoint16(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoInt16"
		expected := int16(1)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		variant.Clear()
		actual, passed := variant.Value().(int16)
		if !passed {
			t.Errorf("%s() did not convert to %s, variant is %s with %v value", method, "int16", variant.VT, variant.Val)
		}
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, actual)
		}
	})
}

func TestIDispatch_goolecomserver_echouint16(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoUInt16"
		expected := uint16(1)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		variant.Clear()
		actual, passed := variant.Value().(uint16)
		if !passed {
			t.Errorf("%s() did not convert to %s, variant is %s with %v value", method, "uint16", variant.VT, variant.Val)
		}
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, actual)
		}
	})
}

func TestIDispatch_goolecomserver_echoint32(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoInt32"
		expected := int32(2)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		variant.Clear()
		actual, passed := variant.Value().(int32)
		if passed {
			if actual != expected {
				t.Errorf("%s() expected %v did not match %v", method, expected, actual)
			}
		}

		actualInt, passed := variant.Value().(int)
		if passed {
			if actualInt != expected {
				t.Errorf("%s() expected %v did not match %v", method, expected, actualInt)
			}
		} else {
			t.Errorf("%s() did not convert to %s, variant is %s with %v value", method, "int32", variant.VT, variant.Val)
		}
	})
}

func TestIDispatch_goolecomserver_echouint32(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoUInt32"
		expected := uint32(4)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		variant.Clear()
		actual, passed := variant.Value().(uint32)
		if passed {
			if actual != expected {
				t.Errorf("%s() expected %v did not match %v", method, expected, actual)
			}
		}

		actualUInt, passed := variant.Value().(uint)
		if passed {
			if actualInt != expected {
				t.Errorf("%s() expected %v did not match %v", method, expected, actualInt)
			}
		} else {
			t.Errorf("%s() did not convert to %s, variant is %s with %v value", method, "uint32", variant.VT, variant.Val)
		}
	})
}

func TestIDispatch_goolecomserver_echoint64(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoInt64"
		expected := int64(1)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		variant.Clear()
		actual, passed := variant.Value().(int64)
		if !passed {
			t.Errorf("%s() did not convert to %s, variant is %s with %v value", method, "int64", variant.VT, variant.Val)
		}
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, actual)
		}
	})
}

func TestIDispatch_goolecomserver_echouint64(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoUInt64"
		expected := uint64(1)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		variant.Clear()
		actual, passed := variant.Value().(uint64)
		if !passed {
			t.Errorf("%s() did not convert to %s, variant is %s with %v value", method, "uint64", variant.VT, variant.Val)
		}
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, actual)
		}
	})
}

func TestIDispatch_goolecomserver_echofloat32(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoFloat32"
		expected := float32(2.2)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		variant.Clear()
		actual, passed := variant.Value().(float32)
		if !passed {
			t.Errorf("%s() did not convert to %s, variant is %s with %v value", method, "float32", variant.VT, variant.Val)
		}
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, actual)
		}
	})
}

func TestIDispatch_goolecomserver_echofloat64(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoFloat64"
		expected := float64(2.2)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		variant.Clear()
		actual, passed := variant.Value().(float64)
		if !passed {
			t.Errorf("%s() did not convert to %s, variant is %s with %v value", method, "float64", variant.VT, variant.Val)
		}
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, actual)
		}
	})
}
<commit_msg>Types must match.<commit_after>// +build windows

package ole

import "testing"

func wrapCOMExecute(t *testing.T, callback func(*testing.T)) {
	defer func() {
		if r := recover(); r != nil {
			t.Error(r)
		}
	}()

	err := CoInitialize(0)
	if err != nil {
		t.Fatal(err)
	}
	defer CoUninitialize()

	callback(t)
}

func wrapDispatch(t *testing.T, ClassID, UnknownInterfaceID, DispatchInterfaceID *GUID, callback func(*testing.T, *IUnknown, *IDispatch)) {
	var unknown *IUnknown
	var dispatch *IDispatch
	var err error

	unknown, err = CreateInstance(ClassID, UnknownInterfaceID)
	if err != nil {
		t.Error(err)
		return
	}
	defer unknown.Release()

	dispatch, err = unknown.QueryInterface(DispatchInterfaceID)
	if err != nil {
		t.Error(err)
		return
	}
	defer dispatch.Release()

	callback(t, unknown, dispatch)
}

func wrapGoOLETestCOMServer(t *testing.T, callback func(*testing.T, *IUnknown, *IDispatch)) {
	wrapCOMExecute(t, func(t *testing.T) {
		wrapDispatch(t, CLSID_COMEchoTestObject, IID_IUnknown, IID_ICOMEchoTestObject, callback)
	})
}

func TestIDispatch_goolecomserver_echostring(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoString"
		expected := "Test String"
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		variant.Clear()
		actual, passed := variant.Value().(string)
		if !passed {
			t.Errorf("%s() did not convert to %s, variant is %s with %v value", method, "string", variant.VT, variant.Val)
		}
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, actual)
		}
	})
}

func TestIDispatch_goolecomserver_echoint8(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoInt8"
		expected := int8(1)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		variant.Clear()
		actual, passed := variant.Value().(int8)
		if !passed {
			t.Errorf("%s() did not convert to %s, variant is %s with %v value", method, "int8", variant.VT, variant.Val)
		}
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, actual)
		}
	})
}

func TestIDispatch_goolecomserver_echouint8(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoUInt8"
		expected := uint8(1)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		variant.Clear()
		actual, passed := variant.Value().(uint8)
		if !passed {
			t.Errorf("%s() did not convert to %s, variant is %s with %v value", method, "uint8", variant.VT, variant.Val)
		}
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, actual)
		}
	})
}

func TestIDispatch_goolecomserver_echoint16(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoInt16"
		expected := int16(1)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		variant.Clear()
		actual, passed := variant.Value().(int16)
		if !passed {
			t.Errorf("%s() did not convert to %s, variant is %s with %v value", method, "int16", variant.VT, variant.Val)
		}
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, actual)
		}
	})
}

func TestIDispatch_goolecomserver_echouint16(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoUInt16"
		expected := uint16(1)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		variant.Clear()
		actual, passed := variant.Value().(uint16)
		if !passed {
			t.Errorf("%s() did not convert to %s, variant is %s with %v value", method, "uint16", variant.VT, variant.Val)
		}
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, actual)
		}
	})
}

func TestIDispatch_goolecomserver_echoint32(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoInt32"
		expected := int32(2)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		variant.Clear()
		actual, passed := variant.Value().(int32)
		if passed {
			if actual != expected {
				t.Errorf("%s() expected %v did not match %v", method, expected, actual)
			}
		}

		actualInt, passed := variant.Value().(int)
		if passed {
			if actualInt != int(expected) {
				t.Errorf("%s() expected %v did not match %v", method, expected, actualInt)
			}
		} else {
			t.Errorf("%s() did not convert to %s, variant is %s with %v value", method, "int32", variant.VT, variant.Val)
		}
	})
}

func TestIDispatch_goolecomserver_echouint32(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoUInt32"
		expected := uint32(4)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		variant.Clear()
		actual, passed := variant.Value().(uint32)
		if passed {
			if actual != expected {
				t.Errorf("%s() expected %v did not match %v", method, expected, actual)
			}
		}

		actualUInt, passed := variant.Value().(uint)
		if passed {
			if actualUInt != uint(expected) {
				t.Errorf("%s() expected %v did not match %v", method, expected, actualUInt)
			}
		} else {
			t.Errorf("%s() did not convert to %s, variant is %s with %v value", method, "uint32", variant.VT, variant.Val)
		}
	})
}

func TestIDispatch_goolecomserver_echoint64(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoInt64"
		expected := int64(1)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		variant.Clear()
		actual, passed := variant.Value().(int64)
		if !passed {
			t.Errorf("%s() did not convert to %s, variant is %s with %v value", method, "int64", variant.VT, variant.Val)
		}
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, actual)
		}
	})
}

func TestIDispatch_goolecomserver_echouint64(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoUInt64"
		expected := uint64(1)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		variant.Clear()
		actual, passed := variant.Value().(uint64)
		if !passed {
			t.Errorf("%s() did not convert to %s, variant is %s with %v value", method, "uint64", variant.VT, variant.Val)
		}
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, actual)
		}
	})
}

func TestIDispatch_goolecomserver_echofloat32(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoFloat32"
		expected := float32(2.2)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		variant.Clear()
		actual, passed := variant.Value().(float32)
		if !passed {
			t.Errorf("%s() did not convert to %s, variant is %s with %v value", method, "float32", variant.VT, variant.Val)
		}
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, actual)
		}
	})
}

func TestIDispatch_goolecomserver_echofloat64(t *testing.T) {
	wrapGoOLETestCOMServer(t, func(t *testing.T, unknown *IUnknown, idispatch *IDispatch) {
		method := "EchoFloat64"
		expected := float64(2.2)
		variant, err := idispatch.CallMethod(method, expected)
		if err != nil {
			t.Error(err)
		}
		variant.Clear()
		actual, passed := variant.Value().(float64)
		if !passed {
			t.Errorf("%s() did not convert to %s, variant is %s with %v value", method, "float64", variant.VT, variant.Val)
		}
		if actual != expected {
			t.Errorf("%s() expected %v did not match %v", method, expected, actual)
		}
	})
}
<|endoftext|>