<commit_before>package curator

import (
	"sync"
	"testing"

	"github.com/samuel/go-zookeeper/zk"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/suite"
)

type CreateBuilderTestSuite struct {
	suite.Suite

	conn        *mockConn
	dialer      *mockZookeeperDialer
	compress    *mockCompressionProvider
	aclProvider *mockACLProvider
	builder     *CuratorFrameworkBuilder
	events      chan zk.Event
	wg          sync.WaitGroup
}

func TestCreateBuilder(t *testing.T) {
	suite.Run(t, new(CreateBuilderTestSuite))
}

func (s *CreateBuilderTestSuite) SetupTest() {
	s.conn = &mockConn{log: s.T().Logf}
	s.dialer = &mockZookeeperDialer{log: s.T().Logf}
	s.compress = &mockCompressionProvider{log: s.T().Logf}
	s.builder = &CuratorFrameworkBuilder{
		ZookeeperDialer:     s.dialer,
		EnsembleProvider:    &fixedEnsembleProvider{"connectString"},
		CompressionProvider: s.compress,
		RetryPolicy:         NewRetryOneTime(0),
		DefaultData:         []byte("default"),
	}
	s.events = make(chan zk.Event)

	s.dialer.On("Dial", s.builder.EnsembleProvider.ConnectionString(), s.builder.ConnectionTimeout, s.builder.CanBeReadOnly).Return(s.conn, s.events, nil).Once()

}

func (s *CreateBuilderTestSuite) TearDownTest() {
	close(s.events)

	s.conn.AssertExpectations(s.T())
	s.dialer.AssertExpectations(s.T())
	s.compress.AssertExpectations(s.T())
}

func (s *CreateBuilderTestSuite) TestCreate() {
	client := s.builder.Build()

	assert.NoError(s.T(), client.Start())

	acls := zk.WorldACL(zk.PermAll)

	s.conn.On("Create", "/node", s.builder.DefaultData, int32(EPHEMERAL), acls).Return("/node", nil).Once()

	path, err := client.Create().WithMode(EPHEMERAL).WithACL(acls...).ForPath("/node")

	assert.Equal(s.T(), "/node", path)
	assert.NoError(s.T(), err)
}

func (s *CreateBuilderTestSuite) TestNamespace() {
	s.builder.Namespace = "parent"

	client := s.builder.Build()

	assert.NoError(s.T(), client.Start())

	acls := zk.WorldACL(zk.PermAll)

	s.conn.On("Create", "/parent/child", s.builder.DefaultData, int32(EPHEMERAL), acls).Return("/parent/child", nil).Once()

	path, err := client.Create().WithMode(EPHEMERAL).WithACL(acls...).ForPath("child")

	assert.Equal(s.T(), "/child", path)
	assert.NoError(s.T(), err)
}

func (s *CreateBuilderTestSuite) TestBackground() {
	client := s.builder.Build()

	assert.NoError(s.T(), client.Start())

	data := []byte("data")
	acls := zk.AuthACL(zk.PermRead)
	ctxt := "context"

	s.conn.On("Create", "/node", data, int32(PERSISTENT), acls).Return("", zk.ErrAPIError).Once()

	s.wg.Add(1)

	path, err := client.Create().WithACL(acls...).InBackgroundWithCallbackAndContext(
		func(client CuratorFramework, event CuratorEvent) error {
			defer s.wg.Done()

			assert.Equal(s.T(), CREATE, event.Type())
			assert.Equal(s.T(), "/node", event.Path())
			assert.Equal(s.T(), data, event.Data())
			assert.Equal(s.T(), acls, event.ACLs())
			assert.EqualError(s.T(), event.Err(), zk.ErrAPIError.Error())
			assert.Equal(s.T(), ctxt, event.Context())

			return nil
		}, ctxt).ForPathWithData("/node", data)

	s.wg.Wait()

	assert.Equal(s.T(), "/node", path)
	assert.NoError(s.T(), err)
}

func (s *CreateBuilderTestSuite) TestCompression() {
	client := s.builder.Build()

	assert.NoError(s.T(), client.Start())

	data := []byte("data")
	compressedData := []byte("compressedData")
	acls := zk.WorldACL(zk.PermAll)

	s.compress.On("Compress", "/node", data).Return(compressedData, nil).Once()
	s.conn.On("Create", "/node", compressedData, int32(PERSISTENT), acls).Return("/node", nil).Once()

	path, err := client.Create().Compressed().WithACL(acls...).ForPathWithData("/node", data)

	assert.Equal(s.T(), "/node", path)
	assert.NoError(s.T(), err)
}

func (s *CreateBuilderTestSuite) TestCreateParents() {
	s.builder.Namespace = "parent"

	client := s.builder.Build()

	assert.NoError(s.T(), client.Start())

	s.conn.On("Create", "/parent/child", s.builder.DefaultData, int32(PERSISTENT), []zk.ACL(nil)).Return("", zk.ErrNoNode).Once()
	s.conn.On("Exists", "/parent").Return(false, nil, nil).Once()
	s.conn.On("Create", "/parent", []byte{}, int32(PERSISTENT), zk.WorldACL(zk.PermAll)).Return("/parent", nil).Once()
	s.conn.On("Create", "/parent/child", s.builder.DefaultData, int32(PERSISTENT), []zk.ACL(nil)).Return("/parent/child", nil).Once()

	path, err := client.Create().CreatingParentsIfNeeded().ForPath("/child")

	assert.Equal(s.T(), "/child", path)
	assert.NoError(s.T(), err)
}
<commit_msg>test namespace for the background mode<commit_after>package curator

import (
	"sync"
	"testing"

	"github.com/samuel/go-zookeeper/zk"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/suite"
)

type CreateBuilderTestSuite struct {
	suite.Suite

	conn        *mockConn
	dialer      *mockZookeeperDialer
	compress    *mockCompressionProvider
	aclProvider *mockACLProvider
	builder     *CuratorFrameworkBuilder
	events      chan zk.Event
	wg          sync.WaitGroup
}

func TestCreateBuilder(t *testing.T) {
	suite.Run(t, new(CreateBuilderTestSuite))
}

func (s *CreateBuilderTestSuite) SetupTest() {
	s.conn = &mockConn{log: s.T().Logf}
	s.dialer = &mockZookeeperDialer{log: s.T().Logf}
	s.compress = &mockCompressionProvider{log: s.T().Logf}
	s.builder = &CuratorFrameworkBuilder{
		ZookeeperDialer:     s.dialer,
		EnsembleProvider:    &fixedEnsembleProvider{"connectString"},
		CompressionProvider: s.compress,
		RetryPolicy:         NewRetryOneTime(0),
		DefaultData:         []byte("default"),
	}
	s.events = make(chan zk.Event)

	s.dialer.On("Dial", s.builder.EnsembleProvider.ConnectionString(), s.builder.ConnectionTimeout, s.builder.CanBeReadOnly).Return(s.conn, s.events, nil).Once()
}

func (s *CreateBuilderTestSuite) TearDownTest() {
	close(s.events)

	s.conn.AssertExpectations(s.T())
	s.dialer.AssertExpectations(s.T())
	s.compress.AssertExpectations(s.T())
}

func (s *CreateBuilderTestSuite) TestCreate() {
	client := s.builder.Build()

	assert.NoError(s.T(), client.Start())

	acls := zk.WorldACL(zk.PermAll)

	s.conn.On("Create", "/node", s.builder.DefaultData, int32(EPHEMERAL), acls).Return("/node", nil).Once()

	path, err := client.Create().WithMode(EPHEMERAL).WithACL(acls...).ForPath("/node")

	assert.Equal(s.T(), "/node", path)
	assert.NoError(s.T(), err)
}

func (s *CreateBuilderTestSuite) TestNamespace() {
	s.builder.Namespace = "parent"

	client := s.builder.Build()

	assert.NoError(s.T(), client.Start())

	acls := zk.WorldACL(zk.PermAll)

	s.conn.On("Create", "/parent/child", s.builder.DefaultData, int32(EPHEMERAL), acls).Return("/parent/child", nil).Once()

	path, err := client.Create().WithMode(EPHEMERAL).WithACL(acls...).ForPath("child")

	assert.Equal(s.T(), "/child", path)
	assert.NoError(s.T(), err)
}

func (s *CreateBuilderTestSuite) TestBackground() {
	s.builder.Namespace = "parent"

	client := s.builder.Build()

	assert.NoError(s.T(), client.Start())

	data := []byte("data")
	acls := zk.AuthACL(zk.PermRead)
	ctxt := "context"

	s.conn.On("Create", "/parent/child", data, int32(PERSISTENT), acls).Return("", zk.ErrAPIError).Once()

	s.wg.Add(1)

	path, err := client.Create().WithACL(acls...).InBackgroundWithCallbackAndContext(
		func(client CuratorFramework, event CuratorEvent) error {
			defer s.wg.Done()

			assert.Equal(s.T(), CREATE, event.Type())
			assert.Equal(s.T(), "/child", event.Path())
			assert.Equal(s.T(), data, event.Data())
			assert.Equal(s.T(), acls, event.ACLs())
			assert.EqualError(s.T(), event.Err(), zk.ErrAPIError.Error())
			assert.Equal(s.T(), ctxt, event.Context())

			return nil
		}, ctxt).ForPathWithData("/child", data)

	s.wg.Wait()

	assert.Equal(s.T(), "/child", path)
	assert.NoError(s.T(), err)
}

func (s *CreateBuilderTestSuite) TestCompression() {
	client := s.builder.Build()

	assert.NoError(s.T(), client.Start())

	data := []byte("data")
	compressedData := []byte("compressedData")
	acls := zk.WorldACL(zk.PermAll)

	s.compress.On("Compress", "/node", data).Return(compressedData, nil).Once()
	s.conn.On("Create", "/node", compressedData, int32(PERSISTENT), acls).Return("/node", nil).Once()

	path, err := client.Create().Compressed().WithACL(acls...).ForPathWithData("/node", data)

	assert.Equal(s.T(), "/node", path)
	assert.NoError(s.T(), err)
}

func (s *CreateBuilderTestSuite) TestCreateParents() {
	s.builder.Namespace = "parent"

	client := s.builder.Build()

	assert.NoError(s.T(), client.Start())

	s.conn.On("Create", "/parent/child", s.builder.DefaultData, int32(PERSISTENT), []zk.ACL(nil)).Return("", zk.ErrNoNode).Once()
	s.conn.On("Exists", "/parent").Return(false, nil, nil).Once()
	s.conn.On("Create", "/parent", []byte{}, int32(PERSISTENT), zk.WorldACL(zk.PermAll)).Return("/parent", nil).Once()
	s.conn.On("Create", "/parent/child", s.builder.DefaultData, int32(PERSISTENT), []zk.ACL(nil)).Return("/parent/child", nil).Once()

	path, err := client.Create().CreatingParentsIfNeeded().ForPath("/child")

	assert.Equal(s.T(), "/child", path)
	assert.NoError(s.T(), err)
}
<|endoftext|>


<commit_before>package list

// ArrayStack XXX
type ArrayStack struct {
	data []interface{}
}

// NewArrayStack returns a pointer to the ArrayStack
func NewArrayStack() *ArrayStack {
	s := &ArrayStack{
		data: make([]interface{}, 0),
	}
	return s
}

// Size return amount of keys in the stack
func (s *ArrayStack) Size() int {
	return len(s.data)
}

// IsEmpty returns true if stack is empty
func (s *ArrayStack) IsEmpty() bool {
	return len(s.data) == 0
}

// Clear removes all elements from the stack
func (s *ArrayStack) Clear() {
	s.data = make([]interface{}, 0)
}

// Push adds element to the top of the stack
func (s *ArrayStack) Push(value interface{}) {
	s.data = append(s.data, value)
}

// PushMany adds elements to the top of the stack
func (s *ArrayStack) PushMany(values ...interface{}) {
	for _, v := range values {
		s.Push(v)
	}
}

// Pop removes and returns top element of the stack
func (s *ArrayStack) Pop() (value interface{}, ok bool) {
	size := len(s.data)
	if size == 0 {
		return nil, false
	}
	value = s.data[size-1]
	s.data = s.data[:size-1]
	return value, true
}

// Top returns top element of the stack
func (s *ArrayStack) Top() (value interface{}, ok bool) {
	size := len(s.data)
	if size == 0 {
		return nil, false
	}
	return s.data[size-1], true
}

// Values returns values presented in stack
func (s *ArrayStack) Values() []interface{} {
	return s.data[:]
}
<commit_msg>stack: ArrayStack PopMany impl<commit_after>package list

// ArrayStack XXX
type ArrayStack struct {
	data []interface{}
}

// NewArrayStack returns a pointer to the ArrayStack
func NewArrayStack() *ArrayStack {
	s := &ArrayStack{
		data: make([]interface{}, 0),
	}
	return s
}

// Size return amount of keys in the stack
func (s *ArrayStack) Size() int {
	return len(s.data)
}

// IsEmpty returns true if stack is empty
func (s *ArrayStack) IsEmpty() bool {
	return len(s.data) == 0
}

// Clear removes all elements from the stack
func (s *ArrayStack) Clear() {
	s.data = make([]interface{}, 0)
}

// Push adds element to the top of the stack
func (s *ArrayStack) Push(value interface{}) {
	s.data = append(s.data, value)
}

// PushMany adds elements to the top of the stack
func (s *ArrayStack) PushMany(values ...interface{}) {
	for _, v := range values {
		s.Push(v)
	}
}

// Pop removes and returns top element of the stack
func (s *ArrayStack) Pop() (value interface{}, ok bool) {
	size := len(s.data)
	if size == 0 {
		return nil, false
	}
	value = s.data[size-1]
	s.data = s.data[:size-1]
	return value, true
}

// PopMany removes and returns top element of the stack
func (s *ArrayStack) PopMany(k int) (values []interface{}, ok bool) {
	if s.Size() == 0 {
		return nil, false
	}
	k = min(k, s.Size())
	values = make([]interface{}, k)
	for i := 0; i < k; i++ {
		value, _ := s.Pop()
		values[i] = value
	}
	return values, true
}

// Top returns top element of the stack
func (s *ArrayStack) Top() (value interface{}, ok bool) {
	size := len(s.data)
	if size == 0 {
		return nil, false
	}
	return s.data[size-1], true
}

// Values returns values presented in stack
func (s *ArrayStack) Values() []interface{} {
	return s.data[:]
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"os"
	"os/exec"
	"strings"
	"unicode"
)

// generates snake case json tags so that you won't need to write them. Can be also exteded to xml or sql tags
func main() {
	fset := token.NewFileSet() // positions are relative to fset
	args := os.Args[1:]
	if len(args) < 2 {
		fmt.Println("Usage : easytags {file_name} {tag_name} {debug (true/false)} \n example: easytags file.go json true")
		return
	}
	debug := false
	if len(args) == 3 {
		if args[2] == "true" {
			debug = true
		}
	}
	tagName := args[1]
	// Parse the file given in arguments
	f, err := parser.ParseFile(fset, args[0], nil, parser.ParseComments)
	if err != nil {
		fmt.Println("Error")
		fmt.Println(err)
		return
	}
	// read entire source file as a slice of lines
	lines, err := readLines(args[0])
	if err != nil {
		fmt.Printf("Error reading file %v \n ", err)
		return
	}
	// range over the objects in the scope of this generated AST and check for StructType. Then range over fields
	// contained in that struct.
	for _, d := range f.Scope.Objects {
		if d.Kind == ast.Typ {
			ts, ok := d.Decl.(*ast.TypeSpec)
			if !ok {
				fmt.Printf("Unknown type without TypeSec: %v", d)
				return
			}

			x, ok := ts.Type.(*ast.StructType)
			if !ok {
				continue
			}
			for _, field := range x.Fields.List {
				line := fset.File(field.Pos()).Line(field.Pos())
				line = line - 1
				if len(field.Names) == 0 {
					continue
				}
				// if tag for field doesn't exists, create one
				if field.Tag == nil {
					name := field.Names[0].String()
					if debug {
						fmt.Printf("Replacing line %s \n ", lines[line])
					}
					lines[line] = fmt.Sprintf("%s %v `%s:\"%s\"`", name, field.Type, tagName, ToSnake(name))
					if debug {
						fmt.Printf("By line : %s \n", lines[line])
					}
				} else if !strings.Contains(field.Tag.Value, fmt.Sprintf("%s:", tagName)) {
					// if tag exists, but doesn't contain target tag
					name := field.Names[0].String()
					if debug {
						fmt.Printf("Replacing line %s \n ", lines[line])
					}
					lines[line] = fmt.Sprintf("%s %v `%s:\"%s\" %s`", name, field.Type, tagName, ToSnake(name), strings.Replace(field.Tag.Value, "`", "", 2))
					if debug {
						fmt.Printf("By line : %s \n", lines[line])
					}

				}

			}
		}
	}
	// overwrite the file with modified version of lines.
	writeLines(lines, args[0])
	cmd := exec.Command("go", "fmt", args[0])
	cmd.Run()
}

// readLines reads a whole file into memory
// and returns a slice of its lines.
// original source : http://stackoverflow.com/questions/5884154/golang-read-text-file-into-string-array-and-write
func readLines(path string) ([]string, error) {
	file, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	var lines []string
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		lines = append(lines, scanner.Text())
	}
	return lines, scanner.Err()
}

// writeLines writes the lines to the given file.
func writeLines(lines []string, path string) error {
	file, err := os.Create(path)
	if err != nil {
		return err
	}
	defer file.Close()

	w := bufio.NewWriter(file)
	for _, line := range lines {
		fmt.Fprintln(w, line)
	}
	return w.Flush()
}

// ToSnake convert the given string to snake case following the Golang format:
// acronyms are converted to lower-case and preceded by an underscore.
// Original source : https://gist.github.com/elwinar/14e1e897fdbe4d3432e1
func ToSnake(in string) string {
	runes := []rune(in)
	length := len(runes)

	var out []rune
	for i := 0; i < length; i++ {
		if i > 0 && unicode.IsUpper(runes[i]) && ((i+1 < length && unicode.IsLower(runes[i+1])) || unicode.IsLower(runes[i-1])) {
			out = append(out, '_')
		}
		out = append(out, unicode.ToLower(runes[i]))
	}

	return string(out)
}
<commit_msg>Use format.Node to write AST to file instead of string manipulation<commit_after>package main

import (
	"bufio"
	"fmt"
	"go/ast"
	"go/format"
	"go/parser"
	"go/token"
	"os"
	"strings"
	"unicode"
)

// generates snake case json tags so that you won't need to write them. Can be also exteded to xml or sql tags
func main() {
	fset := token.NewFileSet() // positions are relative to fset
	args := os.Args[1:]
	if len(args) < 2 {
		fmt.Println("Usage : easytags {file_name} {tag_name} \n example: easytags file.go json true")
		return
	}

	tagName := args[1]
	// Parse the file given in arguments
	f, err := parser.ParseFile(fset, args[0], nil, parser.ParseComments)
	if err != nil {
		fmt.Println("Error")
		fmt.Println(err)
		return
	}

	// range over the objects in the scope of this generated AST and check for StructType. Then range over fields
	// contained in that struct.
	for _, d := range f.Scope.Objects {
		if d.Kind == ast.Typ {
			ts, ok := d.Decl.(*ast.TypeSpec)
			if !ok {
				fmt.Printf("Unknown type without TypeSec: %v", d)
				return
			}

			x, ok := ts.Type.(*ast.StructType)
			if !ok {
				continue
			}
			for _, field := range x.Fields.List {
				if len(field.Names) == 0 {
					continue
				}
				// if tag for field doesn't exists, create one
				if field.Tag == nil {
					name := field.Names[0].String()
					field.Tag = &ast.BasicLit{}
					field.Tag.ValuePos = field.Type.Pos() + 1
					field.Tag.Kind = token.STRING
					field.Tag.Value = fmt.Sprintf("`%s:\"%s\"`", tagName, ToSnake(name))
				} else if !strings.Contains(field.Tag.Value, fmt.Sprintf("%s:", tagName)) {
					// if tag exists, but doesn't contain target tag
					name := field.Names[0].String()
					field.Tag.ValuePos = field.Type.Pos() + 1
					field.Tag.Kind = token.STRING
					field.Tag.Value = fmt.Sprintf("`%s:\"%s\" %s`", tagName, ToSnake(name), strings.Replace(field.Tag.Value, "`", "", 2))
				}
			}
		}
	}

	// overwrite the file with modified version of ast.
	write, err := os.Create(args[0])
	if err != nil {
		fmt.Printf("Error opening file %v", err)
		return
	}
	defer write.Close()
	w := bufio.NewWriter(write)
	err = format.Node(w, fset, f)
	if err != nil {
		fmt.Printf("Error formating file", err)
		return
	}
	w.Flush()
}

// ToSnake convert the given string to snake case following the Golang format:
// acronyms are converted to lower-case and preceded by an underscore.
// Original source : https://gist.github.com/elwinar/14e1e897fdbe4d3432e1
func ToSnake(in string) string {
	runes := []rune(in)
	length := len(runes)

	var out []rune
	for i := 0; i < length; i++ {
		if i > 0 && unicode.IsUpper(runes[i]) && ((i+1 < length && unicode.IsLower(runes[i+1])) || unicode.IsLower(runes[i-1])) {
			out = append(out, '_')
		}
		out = append(out, unicode.ToLower(runes[i]))
	}
	return string(out)
}
<|endoftext|>


<commit_before>package txsizes_test

import (
	"testing"

	"github.com/roasbeef/btcd/wire"
	. "github.com/roasbeef/btcwallet/wallet/internal/txsizes"
)

const (
	p2pkhScriptSize = P2PKHPkScriptSize
	p2shScriptSize  = 23
)

func makeInts(value int, n int) []int {
	v := make([]int, n)
	for i := range v {
		v[i] = value
	}
	return v
}

func TestEstimateSerializeSize(t *testing.T) {
	tests := []struct {
		InputCount           int
		OutputScriptLengths  []int
		AddChangeOutput      bool
		ExpectedSizeEstimate int
	}{
		0: {1, []int{}, false, 159},
		1: {1, []int{p2pkhScriptSize}, false, 193},
		2: {1, []int{}, true, 193},
		3: {1, []int{p2pkhScriptSize}, true, 227},
		4: {1, []int{p2shScriptSize}, false, 191},
		5: {1, []int{p2shScriptSize}, true, 225},

		6:  {2, []int{}, false, 308},
		7:  {2, []int{p2pkhScriptSize}, false, 342},
		8:  {2, []int{}, true, 342},
		9:  {2, []int{p2pkhScriptSize}, true, 376},
		10: {2, []int{p2shScriptSize}, false, 340},
		11: {2, []int{p2shScriptSize}, true, 374},

		// 0xfd is discriminant for 16-bit compact ints, compact int
		// total size increases from 1 byte to 3.
		12: {1, makeInts(p2pkhScriptSize, 0xfc), false, 8727},
		13: {1, makeInts(p2pkhScriptSize, 0xfd), false, 8727 + P2PKHOutputSize + 2},
		14: {1, makeInts(p2pkhScriptSize, 0xfc), true, 8727 + P2PKHOutputSize + 2},
		15: {0xfc, []int{}, false, 37558},
		16: {0xfd, []int{}, false, 37558 + RedeemP2PKHInputSize + 2},
	}
	for i, test := range tests {
		outputs := make([]*wire.TxOut, 0, len(test.OutputScriptLengths))
		for _, l := range test.OutputScriptLengths {
			outputs = append(outputs, &wire.TxOut{PkScript: make([]byte, l)})
		}
		actualEstimate := EstimateSerializeSize(test.InputCount, outputs, test.AddChangeOutput)
		if actualEstimate != test.ExpectedSizeEstimate {
			t.Errorf("Test %d: Got %v: Expected %v", i, actualEstimate, test.ExpectedSizeEstimate)
		}
	}
}
<commit_msg>wallet/size test: add TestEstimateVirtualSize<commit_after>package txsizes_test

import (
	"bytes"
	"encoding/hex"
	"testing"

	"github.com/roasbeef/btcd/wire"
	. "github.com/roasbeef/btcwallet/wallet/internal/txsizes"
)

const (
	p2pkhScriptSize = P2PKHPkScriptSize
	p2shScriptSize  = 23
)

func makeInts(value int, n int) []int {
	v := make([]int, n)
	for i := range v {
		v[i] = value
	}
	return v
}

func TestEstimateSerializeSize(t *testing.T) {
	tests := []struct {
		InputCount           int
		OutputScriptLengths  []int
		AddChangeOutput      bool
		ExpectedSizeEstimate int
	}{
		0: {1, []int{}, false, 159},
		1: {1, []int{p2pkhScriptSize}, false, 193},
		2: {1, []int{}, true, 193},
		3: {1, []int{p2pkhScriptSize}, true, 227},
		4: {1, []int{p2shScriptSize}, false, 191},
		5: {1, []int{p2shScriptSize}, true, 225},

		6:  {2, []int{}, false, 308},
		7:  {2, []int{p2pkhScriptSize}, false, 342},
		8:  {2, []int{}, true, 342},
		9:  {2, []int{p2pkhScriptSize}, true, 376},
		10: {2, []int{p2shScriptSize}, false, 340},
		11: {2, []int{p2shScriptSize}, true, 374},

		// 0xfd is discriminant for 16-bit compact ints, compact int
		// total size increases from 1 byte to 3.
		12: {1, makeInts(p2pkhScriptSize, 0xfc), false, 8727},
		13: {1, makeInts(p2pkhScriptSize, 0xfd), false, 8727 + P2PKHOutputSize + 2},
		14: {1, makeInts(p2pkhScriptSize, 0xfc), true, 8727 + P2PKHOutputSize + 2},
		15: {0xfc, []int{}, false, 37558},
		16: {0xfd, []int{}, false, 37558 + RedeemP2PKHInputSize + 2},
	}
	for i, test := range tests {
		outputs := make([]*wire.TxOut, 0, len(test.OutputScriptLengths))
		for _, l := range test.OutputScriptLengths {
			outputs = append(outputs, &wire.TxOut{PkScript: make([]byte, l)})
		}
		actualEstimate := EstimateSerializeSize(test.InputCount, outputs, test.AddChangeOutput)
		if actualEstimate != test.ExpectedSizeEstimate {
			t.Errorf("Test %d: Got %v: Expected %v", i, actualEstimate, test.ExpectedSizeEstimate)
		}
	}
}

func TestEstimateVirtualSize(t *testing.T) {

	type estimateVSizeTest struct {
		tx             func() (*wire.MsgTx, error)
		p2wkhIns       int
		nestedP2wkhIns int
		change         bool
		result         int
	}

	// TODO(halseth): add tests for more combination out inputs/outputs.
	tests := []estimateVSizeTest{
		// Spending P2WPKH to two outputs. Example adapted from example in BIP-143.
		{
			tx: func() (*wire.MsgTx, error) {
				txHex := "01000000000101ef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a0100000000ffffffff02202cb206000000001976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac9093510d000000001976a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac0247304402203609e17b84f6a7d30c80bfa610b5b4542f32a8a0d5447a12fb1366d7f01cc44a0220573a954c4518331561406f90300e8f3358f51928d43c212a8caed02de67eebee0121025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee635711000000"
				b, err := hex.DecodeString(txHex)
				if err != nil {
					return nil, err
				}
				tx := &wire.MsgTx{}
				err = tx.Deserialize(bytes.NewReader(b))
				if err != nil {
					return nil, err
				}

				return tx, nil
			},
			p2wkhIns: 1,
			result:   147,
		},
		{
			// Spending P2SH-P2WPKH to two outputs. Example adapted from example in BIP-143.
			tx: func() (*wire.MsgTx, error) {
				txHex := "01000000000101db6b1b20aa0fd7b23880be2ecbd4a98130974cf4748fb66092ac4d3ceb1a5477010000001716001479091972186c449eb1ded22b78e40d009bdf0089feffffff02b8b4eb0b000000001976a914a457b684d7f0d539a46a45bbc043f35b59d0d96388ac0008af2f000000001976a914fd270b1ee6abcaea97fea7ad0402e8bd8ad6d77c88ac02473044022047ac8e878352d3ebbde1c94ce3a10d057c24175747116f8288e5d794d12d482f0220217f36a485cae903c713331d877c1f64677e3622ad4010726870540656fe9dcb012103ad1d8e89212f0b92c74d23bb710c00662ad1470198ac48c43f7d6f93a2a2687392040000"
				b, err := hex.DecodeString(txHex)
				if err != nil {
					return nil, err
				}
				tx := &wire.MsgTx{}
				err = tx.Deserialize(bytes.NewReader(b))
				if err != nil {
					return nil, err
				}

				return tx, nil
			},
			nestedP2wkhIns: 1,
			result:         170,
		},
		{
			// Spendin P2WPKH to on output, adding one change output. We reuse
			// the transaction spending to two outputs, removing one of them.
			tx: func() (*wire.MsgTx, error) {
				txHex := "01000000000101ef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a0100000000ffffffff02202cb206000000001976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac9093510d000000001976a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac0247304402203609e17b84f6a7d30c80bfa610b5b4542f32a8a0d5447a12fb1366d7f01cc44a0220573a954c4518331561406f90300e8f3358f51928d43c212a8caed02de67eebee0121025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee635711000000"
				b, err := hex.DecodeString(txHex)
				if err != nil {
					return nil, err
				}
				tx := &wire.MsgTx{}
				err = tx.Deserialize(bytes.NewReader(b))
				if err != nil {
					return nil, err
				}

				// Only keep the first output.
				tx.TxOut = []*wire.TxOut{tx.TxOut[0]}
				return tx, nil
			},
			p2wkhIns: 1,
			change:   true,
			result:   144,
		},
	}

	for _, test := range tests {
		tx, err := test.tx()
		if err != nil {
			t.Fatalf("unable to get test tx: %v", err)
		}

		est := EstimateVirtualSize(0, test.p2wkhIns,
			test.nestedP2wkhIns, tx.TxOut, test.change)

		if est != test.result {
			t.Fatalf("expected estimated vsize to be %d, "+
				"instead got %d", test.result, est)
		}
	}
}
<|endoftext|>


<commit_before>package controllers

import (
	"fmt"
	"net/http"
)

type MainController struct {
}

func (mc *MainController) GetHandler(responseWriter http.ResponseWriter, request *http.Request, parameters map[string]string) {
	responseWriter.Header().Add("Content-Type", "application/json")
	fmt.Fprintf(responseWriter, `{"status":200, "message": "You reached the server"}`)
}
func (mc *MainController) GetVersionHandler(responseWriter http.ResponseWriter, request *http.Request, parameters map[string]string) {
	responseWriter.Header().Add("Content-Type", "application/json")
	fmt.Fprintf(responseWriter, `{"status":200, "version": "0.1.0.17"}`)
}

func NewMainController() MainController {
	return MainController{}
}
<commit_msg>Version 18<commit_after>package controllers

import (
	"fmt"
	"net/http"
)

type MainController struct {
}

func (mc *MainController) GetHandler(responseWriter http.ResponseWriter, request *http.Request, parameters map[string]string) {
	responseWriter.Header().Add("Content-Type", "application/json")
	fmt.Fprintf(responseWriter, `{"status":200, "message": "You reached the server"}`)
}
func (mc *MainController) GetVersionHandler(responseWriter http.ResponseWriter, request *http.Request, parameters map[string]string) {
	responseWriter.Header().Add("Content-Type", "application/json")
	fmt.Fprintf(responseWriter, `{"status":200, "version": "0.1.0.18"}`)
}

func NewMainController() MainController {
	return MainController{}
}
<|endoftext|>


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

import (
	"github.com/ServiceComb/service-center/pkg/util"
	"github.com/ServiceComb/service-center/server/core/backend"
	pb "github.com/ServiceComb/service-center/server/core/proto"
	"github.com/ServiceComb/service-center/server/infra/registry"
	"github.com/coreos/etcd/mvcc/mvccpb"
	"golang.org/x/net/context"
	"strings"
	"sync"
	"time"
)

const (
	DEFAULT_MAX_EVENT_COUNT   = 1000
	DEFAULT_ADD_QUEUE_TIMEOUT = 5 * time.Second
)

var defaultRootKeys map[string]struct{}

func init() {
	defaultRootKeys = make(map[string]struct{}, len(defaultRootKeys))
	for _, root := range TypeRoots {
		defaultRootKeys[root] = struct{}{}
	}
}

type Indexer struct {
	BuildTimeout     time.Duration
	cacher           Cacher
	cacheType        StoreType
	prefixIndex      map[string]map[string]struct{}
	prefixLock       sync.RWMutex
	prefixBuildQueue chan *KvEvent
	goroutine        *util.GoRoutine
	ready            chan struct{}
	isClose          bool
}

func (i *Indexer) Search(ctx context.Context, opts ...registry.PluginOpOption) (*registry.PluginResponse, error) {
	op := registry.OpGet(opts...)

	key := util.BytesToStringWithNoCopy(op.Key)

	if op.Mode == registry.MODE_NO_CACHE ||
		op.Revision > 0 ||
		(op.Offset >= 0 && op.Limit > 0) {
		util.Logger().Debugf("search %s match special options, request etcd server, opts: %s",
			i.cacheType, op)
		return backend.Registry().Do(ctx, opts...)
	}

	if op.Prefix {
		resp, err := i.searchPrefixKeyWithCache(ctx, op)
		if err != nil {
			return nil, err
		}

		if len(resp.Kvs) > 0 || op.Mode == registry.MODE_CACHE {
			return resp, nil
		}

		util.Logger().Debugf("can not find any key from %s cache with prefix, request etcd server, key: %s",
			i.cacheType, key)
		return backend.Registry().Do(ctx, opts...)
	}

	resp := &registry.PluginResponse{
		Action:    op.Action,
		Count:     0,
		Revision:  i.Cache().Version(),
		Succeeded: true,
	}

	if op.CountOnly {
		if i.Cache().Have(key) {
			resp.Count = 1
			return resp, nil
		}
		if op.Mode == registry.MODE_CACHE {
			return resp, nil
		}

		util.Logger().Debugf("%s cache does not store this key, request etcd server, key: %s", i.cacheType, key)
		return backend.Registry().Do(ctx, opts...)
	}

	cacheData := i.Cache().Data(key)
	if cacheData == nil {
		if op.Mode == registry.MODE_CACHE {
			return resp, nil
		}

		util.Logger().Debugf("do not match any key in %s cache store, request etcd server, key: %s",
			i.cacheType, key)
		return backend.Registry().Do(ctx, opts...)
	}

	resp.Count = 1
	resp.Kvs = []*mvccpb.KeyValue{cacheData.(*mvccpb.KeyValue)}
	return resp, nil
}

func (i *Indexer) Cache() Cache {
	return i.cacher.Cache()
}

func (i *Indexer) searchPrefixKeyWithCache(ctx context.Context, op registry.PluginOp) (*registry.PluginResponse, error) {
	resp := &registry.PluginResponse{
		Action:    op.Action,
		Kvs:       []*mvccpb.KeyValue{},
		Count:     0,
		Revision:  i.Cache().Version(),
		Succeeded: true,
	}

	prefix := util.BytesToStringWithNoCopy(op.Key)

	i.prefixLock.RLock()
	resp.Count = int64(i.getPrefixKey(nil, prefix))
	if resp.Count == 0 || op.CountOnly {
		i.prefixLock.RUnlock()
		return resp, nil
	}

	t := time.Now()
	keys := make([]string, 0, resp.Count)
	i.getPrefixKey(&keys, prefix)
	i.prefixLock.RUnlock()

	kvs := make([]*mvccpb.KeyValue, resp.Count)
	idx := 0
	for _, key := range keys {
		c := i.Cache().Data(key) // TODO too slow when big data is requested
		if c == nil {
			// it means resp.Count is not equal to len(keys)
			util.Logger().Warnf(nil, "unexpected nil cache, maybe it is removed, key is %s", key)
			continue
		}
		kvs[idx] = c.(*mvccpb.KeyValue)
		idx++
	}
	util.LogNilOrWarnf(t, "too long to copy data from cache with prefix %s", prefix)

	resp.Kvs = kvs[:idx]
	return resp, nil
}

func (i *Indexer) OnCacheEvent(evt *KvEvent) {
	switch evt.Action {
	case pb.EVT_INIT, pb.EVT_CREATE, pb.EVT_DELETE:
	default:
		return
	}

	if i.isClose {
		return
	}
	defer util.RecoverAndReport()

	ctx, _ := context.WithTimeout(context.Background(), i.BuildTimeout)
	select {
	case <-ctx.Done():
		key := util.BytesToStringWithNoCopy(evt.KV.Key)
		util.Logger().Warnf(nil, "add event to build index queue timed out(%s), key is %s [%s] event",
			i.BuildTimeout, key, evt.Action)
	case i.prefixBuildQueue <- evt:
	}
}

func (i *Indexer) buildIndex() {
	i.goroutine.Do(func(stopCh <-chan struct{}) {
		util.SafeCloseChan(i.ready)
		for {
			select {
			case <-stopCh:
				return
			case evt, ok := <-i.prefixBuildQueue:
				if !ok {
					return
				}
				key := util.BytesToStringWithNoCopy(evt.KV.Key)
				prefix := key[:strings.LastIndex(key, "/")+1]

				i.prefixLock.Lock()
				switch evt.Action {
				case pb.EVT_DELETE:
					i.deletePrefixKey(prefix, key)
				default:
					i.addPrefixKey(prefix, key)
				}
				i.prefixLock.Unlock()

			}
		}
		util.Logger().Debugf("build %s index goroutine is stopped", i.cacheType)
	})
}

func (i *Indexer) getPrefixKey(arr *[]string, prefix string) (count int) {
	keysRef, ok := i.prefixIndex[prefix]
	if !ok {
		return 0
	}

	for key := range keysRef {
		var childs *[]string = nil
		if arr != nil {
			childs = &[]string{}
		}
		n := i.getPrefixKey(childs, key)
		if n == 0 {
			count += len(keysRef)
			if arr != nil {
				for k := range keysRef {
					*arr = append(*arr, k)
				}
			}
			break
		}
		count += n
		if arr != nil {
			*arr = append(*arr, *childs...)
		}
	}
	return count
}

func (i *Indexer) addPrefixKey(prefix, key string) {
	_, ok := defaultRootKeys[key]
	if ok {
		return
	}

	keys, ok := i.prefixIndex[prefix]
	if !ok {
		keys = make(map[string]struct{})
		i.prefixIndex[prefix] = keys
	} else if _, ok := keys[key]; ok {
		return
	}

	keys[key], key = struct{}{}, prefix
	prefix = key[:strings.LastIndex(key[:len(key)-1], "/")+1]

	i.addPrefixKey(prefix, key)
}

func (i *Indexer) deletePrefixKey(prefix, key string) {
	m, ok := i.prefixIndex[prefix]
	if !ok {
		return
	}

	for k := range i.prefixIndex[key] {
		i.deletePrefixKey(key, k)
	}
	delete(m, key)
}

func (i *Indexer) Run() {
	i.prefixLock.Lock()
	if !i.isClose {
		i.prefixLock.Unlock()
		return
	}
	i.isClose = false
	i.prefixLock.Unlock()

	i.buildIndex()

	i.cacher.Run()
}

func (i *Indexer) Stop() {
	i.prefixLock.Lock()
	if i.isClose {
		i.prefixLock.Unlock()
		return
	}
	i.isClose = true
	i.prefixLock.Unlock()

	i.cacher.Stop()

	i.goroutine.Close(true)

	close(i.prefixBuildQueue)

	util.SafeCloseChan(i.ready)
}

func (i *Indexer) Ready() <-chan struct{} {
	<-i.cacher.Ready()
	return i.ready
}

func NewCacheIndexer(t StoreType, cr Cacher) *Indexer {
	return &Indexer{
		BuildTimeout:     DEFAULT_ADD_QUEUE_TIMEOUT,
		cacher:           cr,
		cacheType:        t,
		prefixIndex:      make(map[string]map[string]struct{}, DEFAULT_MAX_EVENT_COUNT),
		prefixBuildQueue: make(chan *KvEvent, DEFAULT_MAX_EVENT_COUNT),
		goroutine:        util.NewGo(make(chan struct{})),
		ready:            make(chan struct{}),
		isClose:          true,
	}
}
<commit_msg>Bug fix: SC panic when received instance DELETE event.<commit_after>//Copyright 2017 Huawei Technologies Co., Ltd
//
//Licensed under the Apache License, Version 2.0 (the "License");
//you may not use this file except in compliance with the License.
//You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
//Unless required by applicable law or agreed to in writing, software
//distributed under the License is distributed on an "AS IS" BASIS,
//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//See the License for the specific language governing permissions and
//limitations under the License.
package store

import (
	"github.com/ServiceComb/service-center/pkg/util"
	"github.com/ServiceComb/service-center/server/core/backend"
	pb "github.com/ServiceComb/service-center/server/core/proto"
	"github.com/ServiceComb/service-center/server/infra/registry"
	"github.com/coreos/etcd/mvcc/mvccpb"
	"golang.org/x/net/context"
	"strings"
	"sync"
	"time"
)

const (
	DEFAULT_MAX_EVENT_COUNT   = 1000
	DEFAULT_ADD_QUEUE_TIMEOUT = 5 * time.Second
)

var defaultRootKeys map[string]struct{}

func init() {
	defaultRootKeys = make(map[string]struct{}, len(defaultRootKeys))
	for _, root := range TypeRoots {
		defaultRootKeys[root] = struct{}{}
	}
}

type Indexer struct {
	BuildTimeout     time.Duration
	cacher           Cacher
	cacheType        StoreType
	prefixIndex      map[string]map[string]struct{}
	prefixLock       sync.RWMutex
	prefixBuildQueue chan *KvEvent
	goroutine        *util.GoRoutine
	ready            chan struct{}
	isClose          bool
}

func (i *Indexer) Search(ctx context.Context, opts ...registry.PluginOpOption) (*registry.PluginResponse, error) {
	op := registry.OpGet(opts...)

	key := util.BytesToStringWithNoCopy(op.Key)

	if op.Mode == registry.MODE_NO_CACHE ||
		op.Revision > 0 ||
		(op.Offset >= 0 && op.Limit > 0) {
		util.Logger().Debugf("search %s match special options, request etcd server, opts: %s",
			i.cacheType, op)
		return backend.Registry().Do(ctx, opts...)
	}

	if op.Prefix {
		resp, err := i.searchPrefixKeyWithCache(ctx, op)
		if err != nil {
			return nil, err
		}

		if len(resp.Kvs) > 0 || op.Mode == registry.MODE_CACHE {
			return resp, nil
		}

		util.Logger().Debugf("can not find any key from %s cache with prefix, request etcd server, key: %s",
			i.cacheType, key)
		return backend.Registry().Do(ctx, opts...)
	}

	resp := &registry.PluginResponse{
		Action:    op.Action,
		Count:     0,
		Revision:  i.Cache().Version(),
		Succeeded: true,
	}

	if op.CountOnly {
		if i.Cache().Have(key) {
			resp.Count = 1
			return resp, nil
		}
		if op.Mode == registry.MODE_CACHE {
			return resp, nil
		}

		util.Logger().Debugf("%s cache does not store this key, request etcd server, key: %s", i.cacheType, key)
		return backend.Registry().Do(ctx, opts...)
	}

	cacheData := i.Cache().Data(key)
	if cacheData == nil {
		if op.Mode == registry.MODE_CACHE {
			return resp, nil
		}

		util.Logger().Debugf("do not match any key in %s cache store, request etcd server, key: %s",
			i.cacheType, key)
		return backend.Registry().Do(ctx, opts...)
	}

	resp.Count = 1
	resp.Kvs = []*mvccpb.KeyValue{cacheData.(*mvccpb.KeyValue)}
	return resp, nil
}

func (i *Indexer) Cache() Cache {
	return i.cacher.Cache()
}

func (i *Indexer) searchPrefixKeyWithCache(ctx context.Context, op registry.PluginOp) (*registry.PluginResponse, error) {
	resp := &registry.PluginResponse{
		Action:    op.Action,
		Kvs:       []*mvccpb.KeyValue{},
		Count:     0,
		Revision:  i.Cache().Version(),
		Succeeded: true,
	}

	prefix := util.BytesToStringWithNoCopy(op.Key)

	i.prefixLock.RLock()
	resp.Count = int64(i.getPrefixKey(nil, prefix))
	if resp.Count == 0 || op.CountOnly {
		i.prefixLock.RUnlock()
		return resp, nil
	}

	t := time.Now()
	keys := make([]string, 0, resp.Count)
	i.getPrefixKey(&keys, prefix)
	i.prefixLock.RUnlock()

	kvs := make([]*mvccpb.KeyValue, resp.Count)
	idx := 0
	for _, key := range keys {
		c := i.Cache().Data(key) // TODO too slow when big data is requested
		if c == nil {
			// it means resp.Count is not equal to len(keys)
			util.Logger().Warnf(nil, "unexpected nil cache, maybe it is removed, key is %s", key)
			continue
		}
		kvs[idx] = c.(*mvccpb.KeyValue)
		idx++
	}
	util.LogNilOrWarnf(t, "too long to copy data from cache with prefix %s", prefix)

	resp.Kvs = kvs[:idx]
	return resp, nil
}

func (i *Indexer) OnCacheEvent(evt *KvEvent) {
	switch evt.Action {
	case pb.EVT_INIT, pb.EVT_CREATE, pb.EVT_DELETE:
	default:
		return
	}

	if i.isClose {
		return
	}
	defer util.RecoverAndReport()

	ctx, _ := context.WithTimeout(context.Background(), i.BuildTimeout)
	select {
	case <-ctx.Done():
		key := util.BytesToStringWithNoCopy(evt.KV.Key)
		util.Logger().Warnf(nil, "add event to build index queue timed out(%s), key is %s [%s] event",
			i.BuildTimeout, key, evt.Action)
	case i.prefixBuildQueue <- evt:
	}
}

func (i *Indexer) buildIndex() {
	i.goroutine.Do(func(stopCh <-chan struct{}) {
		util.SafeCloseChan(i.ready)
		for {
			select {
			case <-stopCh:
				return
			case evt, ok := <-i.prefixBuildQueue:
				if !ok {
					return
				}
				key := util.BytesToStringWithNoCopy(evt.KV.Key)
				prefix := key[:strings.LastIndex(key[:len(key)-1], "/")+1]

				i.prefixLock.Lock()
				switch evt.Action {
				case pb.EVT_DELETE:
					i.deletePrefixKey(prefix, key)
				default:
					i.addPrefixKey(prefix, key)
				}
				i.prefixLock.Unlock()

			}
		}
		util.Logger().Debugf("build %s index goroutine is stopped", i.cacheType)
	})
}

func (i *Indexer) getPrefixKey(arr *[]string, prefix string) (count int) {
	keysRef, ok := i.prefixIndex[prefix]
	if !ok {
		return 0
	}

	for key := range keysRef {
		var childs *[]string = nil
		if arr != nil {
			childs = &[]string{}
		}
		n := i.getPrefixKey(childs, key)
		if n == 0 {
			count += len(keysRef)
			if arr != nil {
				for k := range keysRef {
					*arr = append(*arr, k)
				}
			}
			break
		}
		count += n
		if arr != nil {
			*arr = append(*arr, *childs...)
		}
	}
	return count
}

func (i *Indexer) addPrefixKey(prefix, key string) {
	_, ok := defaultRootKeys[key]
	if ok {
		return
	}

	keys, ok := i.prefixIndex[prefix]
	if !ok {
		keys = make(map[string]struct{})
		i.prefixIndex[prefix] = keys
	} else if _, ok := keys[key]; ok {
		return
	}

	keys[key], key = struct{}{}, prefix
	prefix = key[:strings.LastIndex(key[:len(key)-1], "/")+1]

	i.addPrefixKey(prefix, key)
}

func (i *Indexer) deletePrefixKey(prefix, key string) {
	m, ok := i.prefixIndex[prefix]
	if !ok {
		return
	}

	for k := range i.prefixIndex[key] {
		i.deletePrefixKey(key, k)
	}
	delete(m, key)
}

func (i *Indexer) Run() {
	i.prefixLock.Lock()
	if !i.isClose {
		i.prefixLock.Unlock()
		return
	}
	i.isClose = false
	i.prefixLock.Unlock()

	i.buildIndex()

	i.cacher.Run()
}

func (i *Indexer) Stop() {
	i.prefixLock.Lock()
	if i.isClose {
		i.prefixLock.Unlock()
		return
	}
	i.isClose = true
	i.prefixLock.Unlock()

	i.cacher.Stop()

	i.goroutine.Close(true)

	close(i.prefixBuildQueue)

	util.SafeCloseChan(i.ready)
}

func (i *Indexer) Ready() <-chan struct{} {
	<-i.cacher.Ready()
	return i.ready
}

func NewCacheIndexer(t StoreType, cr Cacher) *Indexer {
	return &Indexer{
		BuildTimeout:     DEFAULT_ADD_QUEUE_TIMEOUT,
		cacher:           cr,
		cacheType:        t,
		prefixIndex:      make(map[string]map[string]struct{}, DEFAULT_MAX_EVENT_COUNT),
		prefixBuildQueue: make(chan *KvEvent, DEFAULT_MAX_EVENT_COUNT),
		goroutine:        util.NewGo(make(chan struct{})),
		ready:            make(chan struct{}),
		isClose:          true,
	}
}
<|endoftext|>


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

package gateway

import (
	. "github.com/smartystreets/goconvey/convey"
	"github.com/thethingsnetwork/core/lorawan/semtech"
	"net"
	"testing"
	"time"
)

func TestStart(t *testing.T) {
	gatewayId := "MyGateway"
	routerAddr := "0.0.0.0:3000"
	gateway, _ := New(gatewayId, routerAddr)
	chout, cherr, err := gateway.Start()

	udpAddr, e := net.ResolveUDPAddr("udp", routerAddr)
	if e != nil {
		t.Errorf("Unexpected error %+v\n", e)
		return
	}

	conn, e := net.DialUDP("udp", nil, udpAddr)
	if e != nil {
		t.Errorf("Unexpected error %+v\n", e)
		return
	}
	defer conn.Close()

	Convey("Given a valid started gateway instance bound to a router", t, func() {
		Convey("Both channels should exist", func() {
			So(cherr, ShouldNotBeNil)
			So(chout, ShouldNotBeNil)
			So(err, ShouldBeNil)
		})

		Convey("A connection should exist", func() {
			So(len(gateway.routers), ShouldEqual, 1)
		})

		Convey("A valid packet should be forwarded", func() {
			packet := semtech.Packet{
				Version:    semtech.VERSION,
				Token:      []byte{0x1, 0x2},
				Identifier: semtech.PUSH_ACK,
			}
			raw, e := semtech.Marshal(&packet)
			if e != nil {
				t.Errorf("Unexpected error %+v\n", e)
				return
			}
			conn.Write(raw)
			So(<-chout, ShouldResemble, packet)
		})

		Convey("An invalid packet should raise an error", func() {
			conn.Write([]byte("Invalid"))
			So(<-cherr, ShouldNotBeNil)
		})

		Convey("It should fail if started one more time", func() {
			_, _, err := gateway.Start()
			So(err, ShouldNotBeNil)
		})
	})

	gateway.Stop()
}

func TestStop(t *testing.T) {
	gatewayId := "MyGateway"
	routerAddr := "0.0.0.0:3000"
	gateway, _ := New(gatewayId, routerAddr)
	Convey("Given a gateway instance", t, func() {
		Convey("It should failed if stopped while not started", func() {
			err := gateway.Stop()
			So(err, ShouldNotBeNil)
		})

		Convey("It should stop correctly after having started", func() {
			gateway.Start()
			time.Sleep(time.Second)
			err := gateway.Stop()

			So(err, ShouldBeNil)
			So(gateway.quit, ShouldBeNil)
			So(len(gateway.routers), ShouldEqual, 0)
		})
	})
}

func TestForward(t *testing.T) {
	gatewayId := "MyGateway"
	routerAddr1 := "0.0.0.0:3000"
	routerAddr2 := "0.0.0.0:3001"

	gateway, _ := New(gatewayId, routerAddr1, routerAddr2)
	chout, cherr, e := gateway.Start()

	if e != nil {
		t.Errorf("Unexpected error %v", e)
		return
	}

	Convey("Given a started gateway bound to two routers", t, func() {
		Convey("When forwarding a valid packet", func() {
			packet := semtech.Packet{
				Version:    semtech.VERSION,
				Token:      []byte{0x1, 0x2},
				Identifier: semtech.PUSH_ACK,
			}
			gateway.Forward(packet)

			Convey("It should be forwarded to both routers", func() {
				var received semtech.Packet
				select {
				case received = <-chout:
				case <-time.After(time.Second):
				}
				So(received, ShouldResemble, packet)
				select {
				case received = <-chout:
				case <-time.After(time.Second):
				}
				So(received, ShouldResemble, packet)
			})
		})

		Convey("When forwarding an invalid packet", func() {
			packet := semtech.Packet{
				Version:    semtech.VERSION,
				Identifier: semtech.PUSH_ACK,
			}
			gateway.Forward(packet)
			Convey("The gateway should trigger an error through the error chan", func() {
				var err error
				select {
				case err = <-cherr:
				case <-time.After(time.Second):
				}
				So(err, ShouldNotBeNil)
			})
		})
	})
}
<commit_msg>[simulators.gateway] Add timeout to channel calls<commit_after>// Copyright © 2015 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

package gateway

import (
	. "github.com/smartystreets/goconvey/convey"
	"github.com/thethingsnetwork/core/lorawan/semtech"
	"net"
	"testing"
	"time"
)

func TestStart(t *testing.T) {
	gatewayId := "MyGateway"
	routerAddr := "0.0.0.0:3000"
	gateway, _ := New(gatewayId, routerAddr)
	chout, cherr, err := gateway.Start()

	udpAddr, e := net.ResolveUDPAddr("udp", routerAddr)
	if e != nil {
		t.Errorf("Unexpected error %+v\n", e)
		return
	}

	conn, e := net.DialUDP("udp", nil, udpAddr)
	if e != nil {
		t.Errorf("Unexpected error %+v\n", e)
		return
	}
	defer conn.Close()

	Convey("Given a valid started gateway instance bound to a router", t, func() {
		Convey("Both channels should exist", func() {
			So(cherr, ShouldNotBeNil)
			So(chout, ShouldNotBeNil)
			So(err, ShouldBeNil)
		})

		Convey("A connection should exist", func() {
			So(len(gateway.routers), ShouldEqual, 1)
		})

		Convey("A valid packet should be forwarded", func() {
			packet := semtech.Packet{
				Version:    semtech.VERSION,
				Token:      []byte{0x1, 0x2},
				Identifier: semtech.PUSH_ACK,
			}
			raw, e := semtech.Marshal(&packet)
			if e != nil {
				t.Errorf("Unexpected error %+v\n", e)
				return
			}
			conn.Write(raw)
			var received semtech.Packet
			select {
			case received = <-chout:
			case <-time.After(time.Second):
			}
			So(received, ShouldResemble, packet)
		})

		Convey("An invalid packet should raise an error", func() {
			conn.Write([]byte("Invalid"))
			var err error
			select {
			case err = <-cherr:
			case <-time.After(time.Second):
			}
			So(err, ShouldNotBeNil)
		})

		Convey("It should fail if started one more time", func() {
			_, _, err := gateway.Start()
			So(err, ShouldNotBeNil)
		})
	})

	gateway.Stop()
}

func TestStop(t *testing.T) {
	gatewayId := "MyGateway"
	routerAddr := "0.0.0.0:3000"
	gateway, _ := New(gatewayId, routerAddr)
	Convey("Given a gateway instance", t, func() {
		Convey("It should failed if stopped while not started", func() {
			err := gateway.Stop()
			So(err, ShouldNotBeNil)
		})

		Convey("It should stop correctly after having started", func() {
			gateway.Start()
			time.Sleep(250 * time.Millisecond)
			err := gateway.Stop()

			So(err, ShouldBeNil)
			So(gateway.quit, ShouldBeNil)
			So(len(gateway.routers), ShouldEqual, 0)
		})
	})
}

func TestForward(t *testing.T) {
	gatewayId := "MyGateway"
	routerAddr1 := "0.0.0.0:3000"
	routerAddr2 := "0.0.0.0:3001"

	gateway, _ := New(gatewayId, routerAddr1, routerAddr2)
	chout, cherr, e := gateway.Start()

	if e != nil {
		t.Errorf("Unexpected error %v", e)
		return
	}

	Convey("Given a started gateway bound to two routers", t, func() {
		Convey("When forwarding a valid packet", func() {
			packet := semtech.Packet{
				Version:    semtech.VERSION,
				Token:      []byte{0x1, 0x2},
				Identifier: semtech.PUSH_ACK,
			}
			gateway.Forward(packet)

			Convey("It should be forwarded to both routers", func() {
				var received semtech.Packet
				select {
				case received = <-chout:
				case <-time.After(time.Second):
				}
				So(received, ShouldResemble, packet)
				select {
				case received = <-chout:
				case <-time.After(time.Second):
				}
				So(received, ShouldResemble, packet)
			})
		})

		Convey("When forwarding an invalid packet", func() {
			packet := semtech.Packet{
				Version:    semtech.VERSION,
				Identifier: semtech.PUSH_ACK,
			}
			gateway.Forward(packet)
			Convey("The gateway should trigger an error through the error chan", func() {
				var err error
				select {
				case err = <-cherr:
				case <-time.After(time.Second):
				}
				So(err, ShouldNotBeNil)
			})
		})
	})
}
<|endoftext|>


<commit_before>package retry

import (
	"net/http"
	"net/http/httptest"
	"sync/atomic"
	"testing"
)

func TestRoundTripper_RoundTripInternalServer(t *testing.T) {

	var counter int32
	testserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
			atomic.AddInt32(&counter, 1)
			t.Log("hit endpoint")
			w.WriteHeader(http.StatusInternalServerError)
	}))

	retryRoundTripper := NewRoundTripper(http.DefaultTransport, .50 , .15 , 3, nil, new(Exp))
	httpClient := new(http.Client)
	httpClient.Transport = retryRoundTripper

	req, err := http.NewRequest(http.MethodGet, testserver.URL, nil )
	if err != nil {
		t.Fatal(err)
	}

	resp, err := httpClient.Do(req)
	if err != nil {
		t.Fatal(err)
	}

	if resp.StatusCode != http.StatusInternalServerError {
		t.Errorf("response is bad, got=%v", resp.StatusCode)
	}

	if counter != 3 {
		t.Errorf("counter is bad, got=%v, want=%v", counter, 3)
	}
}

func TestRoundTripper_RoundTripInternalServerBlacklisted(t *testing.T) {

	var counter int32
	testserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		atomic.AddInt32(&counter, 1)
		t.Log("hit endpoint")
		w.WriteHeader(http.StatusInternalServerError)
	}))

	retryRoundTripper := NewRoundTripper(http.DefaultTransport, .50 , .15 , 3, []int{http.StatusInternalServerError}, new(Exp))
	httpClient := new(http.Client)
	httpClient.Transport = retryRoundTripper

	req, err := http.NewRequest(http.MethodGet, testserver.URL, nil )
	if err != nil {
		t.Fatal(err)
	}

	resp, err := httpClient.Do(req)
	if err != nil {
		t.Fatal(err)
	}

	if resp.StatusCode != http.StatusInternalServerError {
		t.Errorf("response is bad, got=%v", resp.StatusCode)
	}

	if counter != 1 {
		t.Errorf("counter is bad, got=%v, want=%v", counter, 1)
	}
}

func TestRoundTripper_RoundTripStatusOk(t *testing.T) {

	var counter int32
	testserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		atomic.AddInt32(&counter, 1)
		t.Log("hit endpoint")
		w.WriteHeader(http.StatusOK)
	}))

	retryRoundTripper := NewRoundTripper(http.DefaultTransport, .50 , .15 , 3, nil, new(Exp))
	httpClient := new(http.Client)
	httpClient.Transport = retryRoundTripper

	req, err := http.NewRequest(http.MethodGet, testserver.URL, nil )
	if err != nil {
		t.Fatal(err)
	}

	resp, err := httpClient.Do(req)
	if err != nil {
		t.Fatal(err)
	}

	if resp.StatusCode != http.StatusOK {
		t.Errorf("response is bad, got=%v", resp.StatusCode)
	}

	if counter != 1 {
		t.Errorf("counter is bad, got=%v, want=%v", counter, 1)
	}
}<commit_msg>Add test case for roundtripper to response and request body content<commit_after>package retry

import (
	"bytes"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"sync/atomic"
	"testing"
)

func TestRoundTripper_RoundTripInternalServer(t *testing.T) {

	var counter int32
	testserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
			atomic.AddInt32(&counter, 1)
			t.Log("hit endpoint")
			w.WriteHeader(http.StatusInternalServerError)
	}))

	retryRoundTripper := NewRoundTripper(http.DefaultTransport, .50 , .15 , 3, nil, new(Exp))
	httpClient := new(http.Client)
	httpClient.Transport = retryRoundTripper

	req, err := http.NewRequest(http.MethodGet, testserver.URL, nil )
	if err != nil {
		t.Fatal(err)
	}

	resp, err := httpClient.Do(req)
	if err != nil {
		t.Fatal(err)
	}

	if resp.StatusCode != http.StatusInternalServerError {
		t.Errorf("response is bad, got=%v", resp.StatusCode)
	}

	if counter != 3 {
		t.Errorf("counter is bad, got=%v, want=%v", counter, 3)
	}
}

func TestRoundTripper_RoundTripInternalServerBlacklisted(t *testing.T) {

	var counter int32
	testserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		atomic.AddInt32(&counter, 1)
		t.Log("hit endpoint")
		w.WriteHeader(http.StatusInternalServerError)
	}))

	retryRoundTripper := NewRoundTripper(http.DefaultTransport, .50 , .15 , 3, []int{http.StatusInternalServerError}, new(Exp))
	httpClient := new(http.Client)
	httpClient.Transport = retryRoundTripper

	req, err := http.NewRequest(http.MethodGet, testserver.URL, nil )
	if err != nil {
		t.Fatal(err)
	}

	resp, err := httpClient.Do(req)
	if err != nil {
		t.Fatal(err)
	}

	if resp.StatusCode != http.StatusInternalServerError {
		t.Errorf("response is bad, got=%v", resp.StatusCode)
	}

	if counter != 1 {
		t.Errorf("counter is bad, got=%v, want=%v", counter, 1)
	}
}

func TestRoundTripper_RoundTripStatusOk(t *testing.T) {

	var counter int32
	testserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		atomic.AddInt32(&counter, 1)
		t.Log("hit endpoint")
		w.WriteHeader(http.StatusOK)
	}))

	retryRoundTripper := NewRoundTripper(http.DefaultTransport, .50 , .15 , 3, nil, new(Exp))
	httpClient := new(http.Client)
	httpClient.Transport = retryRoundTripper

	req, err := http.NewRequest(http.MethodGet, testserver.URL, nil )
	if err != nil {
		t.Fatal(err)
	}

	resp, err := httpClient.Do(req)
	if err != nil {
		t.Fatal(err)
	}

	if resp.StatusCode != http.StatusOK {
		t.Errorf("response is bad, got=%v", resp.StatusCode)
	}

	if counter != 1 {
		t.Errorf("counter is bad, got=%v, want=%v", counter, 1)
	}
}

func TestRoundTripper_RoundTripJsonStatusOk(t *testing.T) {

	json := `{"hello":"world"}`

	var counter int32
	testserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		atomic.AddInt32(&counter, 1)
		t.Log("hit endpoint")

		b , err := ioutil.ReadAll(req.Body)
		if err != nil {
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		t.Log(string(b))

		count := atomic.LoadInt32(&counter)
		if count == 1 {
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		if string(b) != json {
			w.WriteHeader(http.StatusBadRequest)
			return
		}

		w.WriteHeader(http.StatusOK)
		w.Write([]byte(json))
	}))

	retryRoundTripper := NewRoundTripper(http.DefaultTransport, .50 , .15 , 3, nil, new(Exp))
	httpClient := new(http.Client)
	httpClient.Transport = retryRoundTripper

	req, err := http.NewRequest(http.MethodGet, testserver.URL, bytes.NewBuffer([]byte(json)))
	if err != nil {
		t.Fatal(err)
	}

	resp, err := httpClient.Do(req)
	if err != nil {
		t.Fatal(err)
	}

	if resp.StatusCode != http.StatusOK {
		t.Fatalf("response is bad, got=%v", resp.StatusCode)
	}

	if counter != 2 {
		t.Errorf("counter is bad, got=%v, want=%v", counter, 1)
	}

	b , err := ioutil.ReadAll(resp.Body)
	if err != nil {
		t.Fatalf("response is bad, got=%v", err)
	}

	if string(b) != json {
		t.Fatalf("response body is bad, got=%v", string(b))
	}
}<|endoftext|>


<commit_before>package main

import (
	"net"

	"github.com/davecheney/mdns"
)

func main() {
	// A simple example. Publish an A record for my router at 192.168.1.254.

	mdns.PublishA("router.local.", 3600, net.IPv4(192, 168, 1, 254))

	// A more compilcated example. Publish a SVR record for ssh running on port
	// 22 for my home NAS.

	// Publish an A record as before
	mdns.PublishA("stora.local.", 3600, net.IPv4(192, 168, 1, 200))

	// Publish a PTR record for the _ssh._tcp DNS-SD type
	mdns.PublishPTR("_ssh._tcp.local.", 3600, "stora._ssh._tcp.local.")

	// Publish a SRV record typing the _ssh._tcp record to an A record and a port.
	mdns.PublishSRV("stora._ssh._tcp.local.", 3600, "stora.local.", 22)

	// Most mDNS browsing tools expect a TXT record for the service even if there
	// are not records defined by RFC 2782.
	mdns.PublishTXT("stora._ssh._tcp.local.", 3600, "")

	<-make(chan bool)
}
<commit_msg>Use select{} to block forever, thanks to adg for the tip<commit_after>package main

import (
	"net"

	"github.com/davecheney/mdns"
)

func main() {
	// A simple example. Publish an A record for my router at 192.168.1.254.

	mdns.PublishA("router.local.", 3600, net.IPv4(192, 168, 1, 254))

	// A more compilcated example. Publish a SVR record for ssh running on port
	// 22 for my home NAS.

	// Publish an A record as before
	mdns.PublishA("stora.local.", 3600, net.IPv4(192, 168, 1, 200))

	// Publish a PTR record for the _ssh._tcp DNS-SD type
	mdns.PublishPTR("_ssh._tcp.local.", 3600, "stora._ssh._tcp.local.")

	// Publish a SRV record typing the _ssh._tcp record to an A record and a port.
	mdns.PublishSRV("stora._ssh._tcp.local.", 3600, "stora.local.", 22)

	// Most mDNS browsing tools expect a TXT record for the service even if there
	// are not records defined by RFC 2782.
	mdns.PublishTXT("stora._ssh._tcp.local.", 3600, "")

	select {}
}
<|endoftext|>


<commit_before>// +build linux

package main

import (
	"fmt"
	"github.com/dotcloud/docker/pkg/libcontainer"
	"github.com/dotcloud/docker/pkg/libcontainer/network"
	"github.com/dotcloud/docker/pkg/libcontainer/utils"
	"github.com/dotcloud/docker/pkg/system"
	"github.com/dotcloud/docker/pkg/term"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"syscall"
)

func execCommand(container *libcontainer.Container, tty bool, args []string) (int, error) {
	var (
		master  *os.File
		console string
		err     error

		inPipe           io.WriteCloser
		outPipe, errPipe io.ReadCloser
	)

	if tty {
		master, console, err = createMasterAndConsole()
		if err != nil {
			return -1, err
		}
	}

	// create a pipe so that we can syncronize with the namespaced process and
	// pass the veth name to the child
	r, w, err := os.Pipe()
	if err != nil {
		return -1, err
	}
	system.UsetCloseOnExec(r.Fd())

	command := createCommand(container, console, r.Fd(), args)

	if !tty {
		inPipe, err = command.StdinPipe()
		if err != nil {
			return -1, err
		}
		outPipe, err = command.StdoutPipe()
		if err != nil {
			return -1, err
		}
		errPipe, err = command.StderrPipe()
		if err != nil {
			return -1, err
		}
	}

	if err := command.Start(); err != nil {
		return -1, err
	}

	if err := writePidFile(command); err != nil {
		command.Process.Kill()
		return -1, err
	}
	defer deletePidFile()

	// Do this before syncing with child so that no children
	// can escape the cgroup
	if container.Cgroups != nil {
		if err := container.Cgroups.Apply(command.Process.Pid); err != nil {
			command.Process.Kill()
			return -1, err
		}
	}

	if container.Network != nil {
		vethPair, err := initializeContainerVeth(container.Network.Bridge, command.Process.Pid)
		if err != nil {
			return -1, err
		}
		sendVethName(w, vethPair)
	}

	// Sync with child
	w.Close()
	r.Close()

	if tty {
		go io.Copy(os.Stdout, master)
		go io.Copy(master, os.Stdin)
		state, err := setupWindow(master)
		if err != nil {
			command.Process.Kill()
			return -1, err
		}
		defer term.RestoreTerminal(os.Stdin.Fd(), state)
	} else {
		go io.Copy(inPipe, os.Stdin)
		go io.Copy(os.Stdout, outPipe)
		go io.Copy(os.Stderr, errPipe)
	}

	if err := command.Wait(); err != nil {
		if _, ok := err.(*exec.ExitError); !ok {
			return -1, err
		}
	}
	return command.ProcessState.Sys().(syscall.WaitStatus).ExitStatus(), nil
}

// sendVethName writes the veth pair name to the child's stdin then closes the
// pipe so that the child stops waiting for more data
func sendVethName(pipe io.Writer, name string) {
	fmt.Fprint(pipe, name)
}

// initializeContainerVeth will create a veth pair and setup the host's
// side of the pair by setting the specified bridge as the master and bringing
// up the interface.
//
// Then will with set the other side of the veth pair into the container's namespaced
// using the pid and returns the veth's interface name to provide to the container to
// finish setting up the interface inside the namespace
func initializeContainerVeth(bridge string, nspid int) (string, error) {
	name1, name2, err := createVethPair()
	if err != nil {
		return "", err
	}
	if err := network.SetInterfaceMaster(name1, bridge); err != nil {
		return "", err
	}
	if err := network.InterfaceUp(name1); err != nil {
		return "", err
	}
	if err := network.SetInterfaceInNamespacePid(name2, nspid); err != nil {
		return "", err
	}
	return name2, nil
}

func setupWindow(master *os.File) (*term.State, error) {
	ws, err := term.GetWinsize(os.Stdin.Fd())
	if err != nil {
		return nil, err
	}
	if err := term.SetWinsize(master.Fd(), ws); err != nil {
		return nil, err
	}
	return term.SetRawTerminal(os.Stdin.Fd())
}

// createMasterAndConsole will open /dev/ptmx on the host and retreive the
// pts name for use as the pty slave inside the container
func createMasterAndConsole() (*os.File, string, error) {
	master, err := os.OpenFile("/dev/ptmx", syscall.O_RDWR|syscall.O_NOCTTY|syscall.O_CLOEXEC, 0)
	if err != nil {
		return nil, "", err
	}
	console, err := system.Ptsname(master)
	if err != nil {
		return nil, "", err
	}
	if err := system.Unlockpt(master); err != nil {
		return nil, "", err
	}
	return master, console, nil
}

// createVethPair will automatically generage two random names for
// the veth pair and ensure that they have been created
func createVethPair() (name1 string, name2 string, err error) {
	name1, err = utils.GenerateRandomName("dock", 4)
	if err != nil {
		return
	}
	name2, err = utils.GenerateRandomName("dock", 4)
	if err != nil {
		return
	}
	if err = network.CreateVethPair(name1, name2); err != nil {
		return
	}
	return
}

// writePidFile writes the namespaced processes pid to .nspid in the rootfs for the container
func writePidFile(command *exec.Cmd) error {
	return ioutil.WriteFile(".nspid", []byte(fmt.Sprint(command.Process.Pid)), 0655)
}

func deletePidFile() error {
	return os.Remove(".nspid")
}

// createCommand will return an exec.Cmd with the Cloneflags set to the proper namespaces
// defined on the container's configuration and use the current binary as the init with the
// args provided
func createCommand(container *libcontainer.Container, console string, pipe uintptr, args []string) *exec.Cmd {
	command := exec.Command("nsinit", append([]string{"-console", console, "-pipe", fmt.Sprint(pipe), "init"}, args...)...)
	command.SysProcAttr = &syscall.SysProcAttr{
		Cloneflags: uintptr(getNamespaceFlags(container.Namespaces)),
	}
	return command
}
<commit_msg>Make sure to close the pipe upon ctrl-d<commit_after>// +build linux

package main

import (
	"fmt"
	"github.com/dotcloud/docker/pkg/libcontainer"
	"github.com/dotcloud/docker/pkg/libcontainer/network"
	"github.com/dotcloud/docker/pkg/libcontainer/utils"
	"github.com/dotcloud/docker/pkg/system"
	"github.com/dotcloud/docker/pkg/term"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"syscall"
)

func execCommand(container *libcontainer.Container, tty bool, args []string) (int, error) {
	var (
		master  *os.File
		console string
		err     error

		inPipe           io.WriteCloser
		outPipe, errPipe io.ReadCloser
	)

	if tty {
		master, console, err = createMasterAndConsole()
		if err != nil {
			return -1, err
		}
	}

	// create a pipe so that we can syncronize with the namespaced process and
	// pass the veth name to the child
	r, w, err := os.Pipe()
	if err != nil {
		return -1, err
	}
	system.UsetCloseOnExec(r.Fd())

	command := createCommand(container, console, r.Fd(), args)

	if !tty {
		inPipe, err = command.StdinPipe()
		if err != nil {
			return -1, err
		}
		outPipe, err = command.StdoutPipe()
		if err != nil {
			return -1, err
		}
		errPipe, err = command.StderrPipe()
		if err != nil {
			return -1, err
		}
	}

	if err := command.Start(); err != nil {
		return -1, err
	}

	if err := writePidFile(command); err != nil {
		command.Process.Kill()
		return -1, err
	}
	defer deletePidFile()

	// Do this before syncing with child so that no children
	// can escape the cgroup
	if container.Cgroups != nil {
		if err := container.Cgroups.Apply(command.Process.Pid); err != nil {
			command.Process.Kill()
			return -1, err
		}
	}

	if container.Network != nil {
		vethPair, err := initializeContainerVeth(container.Network.Bridge, command.Process.Pid)
		if err != nil {
			return -1, err
		}
		sendVethName(w, vethPair)
	}

	// Sync with child
	w.Close()
	r.Close()

	if tty {
		go io.Copy(os.Stdout, master)
		go io.Copy(master, os.Stdin)
		state, err := setupWindow(master)
		if err != nil {
			command.Process.Kill()
			return -1, err
		}
		defer term.RestoreTerminal(os.Stdin.Fd(), state)
	} else {
		go func() {
			defer inPipe.Close()
			io.Copy(inPipe, os.Stdin)
		}()
		go io.Copy(os.Stdout, outPipe)
		go io.Copy(os.Stderr, errPipe)
	}

	if err := command.Wait(); err != nil {
		if _, ok := err.(*exec.ExitError); !ok {
			return -1, err
		}
	}

	return command.ProcessState.Sys().(syscall.WaitStatus).ExitStatus(), nil
}

// sendVethName writes the veth pair name to the child's stdin then closes the
// pipe so that the child stops waiting for more data
func sendVethName(pipe io.Writer, name string) {
	fmt.Fprint(pipe, name)
}

// initializeContainerVeth will create a veth pair and setup the host's
// side of the pair by setting the specified bridge as the master and bringing
// up the interface.
//
// Then will with set the other side of the veth pair into the container's namespaced
// using the pid and returns the veth's interface name to provide to the container to
// finish setting up the interface inside the namespace
func initializeContainerVeth(bridge string, nspid int) (string, error) {
	name1, name2, err := createVethPair()
	if err != nil {
		return "", err
	}
	if err := network.SetInterfaceMaster(name1, bridge); err != nil {
		return "", err
	}
	if err := network.InterfaceUp(name1); err != nil {
		return "", err
	}
	if err := network.SetInterfaceInNamespacePid(name2, nspid); err != nil {
		return "", err
	}
	return name2, nil
}

func setupWindow(master *os.File) (*term.State, error) {
	ws, err := term.GetWinsize(os.Stdin.Fd())
	if err != nil {
		return nil, err
	}
	if err := term.SetWinsize(master.Fd(), ws); err != nil {
		return nil, err
	}
	return term.SetRawTerminal(os.Stdin.Fd())
}

// createMasterAndConsole will open /dev/ptmx on the host and retreive the
// pts name for use as the pty slave inside the container
func createMasterAndConsole() (*os.File, string, error) {
	master, err := os.OpenFile("/dev/ptmx", syscall.O_RDWR|syscall.O_NOCTTY|syscall.O_CLOEXEC, 0)
	if err != nil {
		return nil, "", err
	}
	console, err := system.Ptsname(master)
	if err != nil {
		return nil, "", err
	}
	if err := system.Unlockpt(master); err != nil {
		return nil, "", err
	}
	return master, console, nil
}

// createVethPair will automatically generage two random names for
// the veth pair and ensure that they have been created
func createVethPair() (name1 string, name2 string, err error) {
	name1, err = utils.GenerateRandomName("dock", 4)
	if err != nil {
		return
	}
	name2, err = utils.GenerateRandomName("dock", 4)
	if err != nil {
		return
	}
	if err = network.CreateVethPair(name1, name2); err != nil {
		return
	}
	return
}

// writePidFile writes the namespaced processes pid to .nspid in the rootfs for the container
func writePidFile(command *exec.Cmd) error {
	return ioutil.WriteFile(".nspid", []byte(fmt.Sprint(command.Process.Pid)), 0655)
}

func deletePidFile() error {
	return os.Remove(".nspid")
}

// createCommand will return an exec.Cmd with the Cloneflags set to the proper namespaces
// defined on the container's configuration and use the current binary as the init with the
// args provided
func createCommand(container *libcontainer.Container, console string, pipe uintptr, args []string) *exec.Cmd {
	command := exec.Command("nsinit", append([]string{"-console", console, "-pipe", fmt.Sprint(pipe), "init"}, args...)...)
	command.SysProcAttr = &syscall.SysProcAttr{
		Cloneflags: uintptr(getNamespaceFlags(container.Namespaces)),
	}
	return command
}
<|endoftext|>


<commit_before>package pdfingestion

import (
	"net/http"
	"path/filepath"
	"testing"

	"cloud.google.com/go/storage"
	assert "github.com/stretchr/testify/require"
	"go.skia.org/infra/go/auth"
	"go.skia.org/infra/go/fileutil"
	"go.skia.org/infra/go/gs"
	"go.skia.org/infra/go/ingestion"
	"go.skia.org/infra/go/sharedconfig"
	"go.skia.org/infra/go/testutils"
	"go.skia.org/infra/go/util"
	"go.skia.org/infra/golden/go/goldingestion"
	"golang.org/x/net/context"
	"google.golang.org/api/option"
)

const (
	// name of the input file containing test data.
	TEST_INGESTION_FILE = "testdata/dm.json"

	// bucket where the results are written.
	TEST_BUCKET = "skia-infra-testdata"

	// dirctories with the input and output.
	IMAGES_IN_DIR  = "pdfingestion/dm-images-v1"
	IMAGES_OUT_DIR = "pdfingestion/output/images"
	JSON_OUT_DIR   = "pdfingestion/output/json"
	CACHE_DIR      = "./pdfcache"
)

func TestPDFProcessor(t *testing.T) {
	testutils.MediumTest(t)
	testutils.SkipIfShort(t)

	// Get the service account client from meta data or a local config file.
	client, err := auth.NewJWTServiceAccountClient("", auth.DEFAULT_JWT_FILENAME, nil, storage.ScopeFullControl)
	assert.NoError(t, err)

	cacheDir, err := fileutil.EnsureDirExists(CACHE_DIR)
	assert.NoError(t, err)

	// Clean up after the test.
	defer func() {
		defer util.RemoveAll(cacheDir)
		deleteFolderContent(t, TEST_BUCKET, IMAGES_OUT_DIR, client)
		deleteFolderContent(t, TEST_BUCKET, JSON_OUT_DIR, client)
	}()

	// Configure the processor.
	ingesterConf := &sharedconfig.IngesterConfig{
		ExtraParams: map[string]string{
			CONFIG_INPUT_IMAGES_BUCKET:  TEST_BUCKET,
			CONFIG_INPUT_IMAGES_DIR:     IMAGES_IN_DIR,
			CONFIG_OUTPUT_JSON_BUCKET:   TEST_BUCKET,
			CONFIG_OUTPUT_JSON_DIR:      JSON_OUT_DIR,
			CONFIG_OUTPUT_IMAGES_BUCKET: TEST_BUCKET,
			CONFIG_OUTPUT_IMAGES_DIR:    IMAGES_OUT_DIR,
			CONFIG_PDF_CACHEDIR:         cacheDir,
		},
	}
	processor, err := newPDFProcessor(nil, ingesterConf, client)
	assert.NoError(t, err)

	// Load the example file and process it.
	fsResult, err := ingestion.FileSystemResult(TEST_INGESTION_FILE, "./")
	assert.NoError(t, err)

	err = processor.Process(fsResult)
	assert.NoError(t, err)

	// Fetch the json output and parse it.
	pProcessor := processor.(*pdfProcessor)

	// download the result.
	resultFileName := filepath.Join(CACHE_DIR, "result-file.json")
	assert.NoError(t, pProcessor.download(TEST_BUCKET, JSON_OUT_DIR, fsResult.Name(), resultFileName))

	// Make sure we get the expected result.
	fsResult, err = ingestion.FileSystemResult(TEST_INGESTION_FILE, "./")
	assert.NoError(t, err)
	r, err := fsResult.Open()
	assert.NoError(t, err)
	fsDMResults, err := goldingestion.ParseDMResultsFromReader(r, TEST_INGESTION_FILE)
	assert.NoError(t, err)

	foundResult, err := ingestion.FileSystemResult(resultFileName, "./")
	assert.NoError(t, err)
	r, err = foundResult.Open()
	assert.NoError(t, err)
	foundDMResults, err := goldingestion.ParseDMResultsFromReader(r, foundResult.Name())
	assert.NoError(t, err)

	dmResult1 := *fsDMResults
	dmResult2 := *foundDMResults
	dmResult1.Results = nil
	dmResult2.Results = nil
	assert.Equal(t, dmResult1, dmResult2)

	foundIdx := 0
	srcResults := fsDMResults.Results
	tgtResults := foundDMResults.Results
	for _, result := range srcResults {
		assert.True(t, foundIdx < len(tgtResults))
		if result.Options["ext"] == "pdf" {
			for ; (foundIdx < len(tgtResults)) && (result.Key["name"] == tgtResults[foundIdx].Key["name"]); foundIdx++ {
				assert.True(t, tgtResults[foundIdx].Key["rasterizer"] != "")
				delete(tgtResults[foundIdx].Key, "rasterizer")
				assert.Equal(t, result.Key, tgtResults[foundIdx].Key)
				assert.Equal(t, "png", tgtResults[foundIdx].Options["ext"])
			}
		}
	}
	assert.Equal(t, len(foundDMResults.Results), foundIdx)
}

// deleteFolderContent removes all content ing the given GS bucket/foldername.
func deleteFolderContent(t *testing.T, bucket, folderName string, client *http.Client) {
	ctx := context.Background()
	cStorage, err := storage.NewClient(ctx, option.WithHTTPClient(client))
	assert.NoError(t, err)

	assert.NoError(t, gs.DeleteAllFilesInDir(cStorage, bucket, folderName, 1))
}
<commit_msg>Fix bug in PDF processor tests<commit_after>package pdfingestion

import (
	"net/http"
	"path/filepath"
	"testing"

	"cloud.google.com/go/storage"
	assert "github.com/stretchr/testify/require"
	"go.skia.org/infra/go/auth"
	"go.skia.org/infra/go/fileutil"
	"go.skia.org/infra/go/gs"
	"go.skia.org/infra/go/ingestion"
	"go.skia.org/infra/go/sharedconfig"
	"go.skia.org/infra/go/testutils"
	"go.skia.org/infra/go/util"
	"go.skia.org/infra/golden/go/goldingestion"
	"golang.org/x/net/context"
	"google.golang.org/api/option"
)

const (
	// name of the input file containing test data.
	TEST_INGESTION_FILE = "testdata/dm.json"

	// bucket where the results are written.
	TEST_BUCKET = "skia-infra-testdata"

	// dirctories with the input and output.
	IMAGES_IN_DIR  = "pdfingestion/dm-images-v1"
	IMAGES_OUT_DIR = "pdfingestion/output/images"
	JSON_OUT_DIR   = "pdfingestion/output/json"
	CACHE_DIR      = "./pdfcache"
)

func TestPDFProcessor(t *testing.T) {
	testutils.MediumTest(t)
	testutils.SkipIfShort(t)

	// Get the service account client from meta data or a local config file.
	client, err := auth.NewJWTServiceAccountClient("", auth.DEFAULT_JWT_FILENAME, nil, storage.ScopeFullControl)
	assert.NoError(t, err)

	cacheDir, err := fileutil.EnsureDirExists(CACHE_DIR)
	assert.NoError(t, err)

	// Clean up after the test.
	defer func() {
		defer util.RemoveAll(cacheDir)
		deleteFolderContent(t, TEST_BUCKET, IMAGES_OUT_DIR, client)
		deleteFolderContent(t, TEST_BUCKET, JSON_OUT_DIR, client)
	}()

	// Configure the processor.
	ingesterConf := &sharedconfig.IngesterConfig{
		ExtraParams: map[string]string{
			CONFIG_INPUT_IMAGES_BUCKET:  TEST_BUCKET,
			CONFIG_INPUT_IMAGES_DIR:     IMAGES_IN_DIR,
			CONFIG_OUTPUT_JSON_BUCKET:   TEST_BUCKET,
			CONFIG_OUTPUT_JSON_DIR:      JSON_OUT_DIR,
			CONFIG_OUTPUT_IMAGES_BUCKET: TEST_BUCKET,
			CONFIG_OUTPUT_IMAGES_DIR:    IMAGES_OUT_DIR,
			CONFIG_PDF_CACHEDIR:         cacheDir,
		},
	}
	processor, err := newPDFProcessor(nil, ingesterConf, client)
	assert.NoError(t, err)

	// Load the example file and process it.
	fsResult, err := ingestion.FileSystemResult(TEST_INGESTION_FILE, "./")
	assert.NoError(t, err)

	err = processor.Process(fsResult)
	assert.NoError(t, err)

	// Fetch the json output and parse it.
	pProcessor := processor.(*pdfProcessor)

	// download the result.
	resultFileName := filepath.Join(CACHE_DIR, "result-file.json")
	assert.NoError(t, pProcessor.download(TEST_BUCKET, JSON_OUT_DIR, fsResult.Name(), resultFileName))

	// Make sure we get the expected result.
	fsResult, err = ingestion.FileSystemResult(TEST_INGESTION_FILE, "./")
	assert.NoError(t, err)
	r, err := fsResult.Open()
	assert.NoError(t, err)
	fsDMResults, err := goldingestion.ParseDMResultsFromReader(r, TEST_INGESTION_FILE)
	assert.NoError(t, err)

	foundResult, err := ingestion.FileSystemResult(resultFileName, "./")
	assert.NoError(t, err)
	r, err = foundResult.Open()
	assert.NoError(t, err)
	foundDMResults, err := goldingestion.ParseDMResultsFromReader(r, TEST_INGESTION_FILE)
	assert.NoError(t, err)

	dmResult1 := *fsDMResults
	dmResult2 := *foundDMResults
	dmResult1.Results = nil
	dmResult2.Results = nil
	assert.Equal(t, dmResult1, dmResult2)

	foundIdx := 0
	srcResults := fsDMResults.Results
	tgtResults := foundDMResults.Results
	for _, result := range srcResults {
		assert.True(t, foundIdx < len(tgtResults))
		if result.Options["ext"] == "pdf" {
			for ; (foundIdx < len(tgtResults)) && (result.Key["name"] == tgtResults[foundIdx].Key["name"]); foundIdx++ {
				assert.True(t, tgtResults[foundIdx].Key["rasterizer"] != "")
				delete(tgtResults[foundIdx].Key, "rasterizer")
				assert.Equal(t, result.Key, tgtResults[foundIdx].Key)
				assert.Equal(t, "png", tgtResults[foundIdx].Options["ext"])
			}
		}
	}
	assert.Equal(t, len(foundDMResults.Results), foundIdx)
}

// deleteFolderContent removes all content ing the given GS bucket/foldername.
func deleteFolderContent(t *testing.T, bucket, folderName string, client *http.Client) {
	ctx := context.Background()
	cStorage, err := storage.NewClient(ctx, option.WithHTTPClient(client))
	assert.NoError(t, err)

	assert.NoError(t, gs.DeleteAllFilesInDir(cStorage, bucket, folderName, 1))
}
<|endoftext|>


<commit_before>package scene

import (
	"image"
	"math"

	"github.com/pankona/gomo-simra/examples/sample2/scene/config"
	"github.com/pankona/gomo-simra/peer"
)

type CtrlTrial struct {
	ball peer.PeerSprite
}

func (self *CtrlTrial) Initialize() {
	peer.LogDebug("[IN]")

	peer.SetDesiredScreenSize(config.SCREEN_WIDTH, config.SCREEN_HEIGHT)
	peer.GetTouchPeer().AddTouchListener(self)

	// initialize sprites
	self.initBall()

	peer.LogDebug("[OUT]")
}

func (self *CtrlTrial) initBall() {
	// add ball sprite
	self.ball.W = float32(48)
	self.ball.H = float32(48)

	// put center of screen at start
	self.ball.X = config.SCREEN_WIDTH / 2
	self.ball.Y = config.SCREEN_HEIGHT / 2

	tex_ball := peer.GetGLPeer().LoadTexture("ball.png",
		image.Rect(0, 0, int(self.ball.W), int(self.ball.H)))
	peer.GetGLPeer().AddSprite(&self.ball, tex_ball)
}

var degree float32 = 0

func (self *CtrlTrial) Drive() {
	degree += 1
	if degree >= 360 {
		degree = 0
	}
	self.ball.R = float32(degree) * math.Pi / 180
}

func (self *CtrlTrial) OnTouchBegin(x, y float32) {
}

func (self *CtrlTrial) OnTouchMove(x, y float32) {
}

func (self *CtrlTrial) OnTouchEnd(x, y float32) {
}
<commit_msg>[#20] put controller on left bottom of screen<commit_after>package scene

import (
	"image"
	"math"

	"github.com/pankona/gomo-simra/examples/sample2/scene/config"
	"github.com/pankona/gomo-simra/peer"
)

type CtrlTrial struct {
	ball     peer.PeerSprite
	ctrlup   peer.PeerSprite
	ctrldown peer.PeerSprite
}

func (self *CtrlTrial) Initialize() {
	peer.LogDebug("[IN]")

	peer.SetDesiredScreenSize(config.SCREEN_WIDTH, config.SCREEN_HEIGHT)
	peer.GetTouchPeer().AddTouchListener(self)

	// initialize sprites
	self.initSprites()

	peer.LogDebug("[OUT]")
}

func (self *CtrlTrial) initSprites() {
	self.initBall()
	self.initCtrlUp()
	self.initCtrlDown()
}

func (self *CtrlTrial) initBall() {
	// set size of ball
	self.ball.W = float32(48)
	self.ball.H = float32(48)

	// put center of screen at start
	self.ball.X = config.SCREEN_WIDTH / 2
	self.ball.Y = config.SCREEN_HEIGHT / 2

	tex := peer.GetGLPeer().LoadTexture("ball.png",
		image.Rect(0, 0, int(self.ball.W), int(self.ball.H)))
	peer.GetGLPeer().AddSprite(&self.ball, tex)
}

const (
	CTRL_MARGIN_LEFT    = 10
	CTRL_MARGIN_BOTTOM  = 10
	CTRL_MARGIN_BETWEEN = 10
)

func (self *CtrlTrial) initCtrlUp() {
	// set size of CtrlUp
	self.ctrlup.W = float32(120)
	self.ctrlup.H = float32(120)

	// put CtrlUp on left bottom
	self.ctrlup.X = (self.ctrlup.W / 2) + 10
	self.ctrlup.Y =
		config.SCREEN_HEIGHT - (self.ctrlup.H / 2) -
			self.ctrlup.H - CTRL_MARGIN_BOTTOM - CTRL_MARGIN_BETWEEN

	// add sprite to glpeer
	tex := peer.GetGLPeer().LoadTexture("arrow.png",
		image.Rect(0, 0, int(self.ctrlup.W), int(self.ctrlup.H)))
	peer.GetGLPeer().AddSprite(&self.ctrlup, tex)
}

func (self *CtrlTrial) initCtrlDown() {
	// set size of CtrlDown
	self.ctrldown.W = float32(120)
	self.ctrldown.H = float32(120)

	// put CtrlDown on left bottom
	self.ctrldown.X = (self.ctrldown.W / 2) + 10
	self.ctrldown.Y =
		config.SCREEN_HEIGHT - (self.ctrldown.H / 2) - CTRL_MARGIN_BOTTOM

	// rotate arrow to indicate down control
	self.ctrldown.R = math.Pi

	// add sprite to glpeer
	tex := peer.GetGLPeer().LoadTexture("arrow.png",
		image.Rect(0, 0, int(self.ctrldown.W), int(self.ctrldown.H)))
	peer.GetGLPeer().AddSprite(&self.ctrldown, tex)
}

var degree float32 = 0

func (self *CtrlTrial) Drive() {
	degree += 1
	if degree >= 360 {
		degree = 0
	}
	self.ball.R = float32(degree) * math.Pi / 180
}

func (self *CtrlTrial) OnTouchBegin(x, y float32) {
}

func (self *CtrlTrial) OnTouchMove(x, y float32) {
}

func (self *CtrlTrial) OnTouchEnd(x, y float32) {
}
<|endoftext|>


<commit_before>package groupdb

type DayID uint32

func MakeDayID(year, month, day int) DayID {
	return (DayID(year)<<16)|(DayID(month)<<8)|DayID(day)
}

func (d DayID) Date() (year int, month int, day int) {
	year = int((d>>16)&0xffff)
	month = int((d>>8)&0xff)
	day = int(d&0xff)
	return
}

type DayProvider func() DayID

type Group struct{
	Name  string
	Desc  string
	Low   int64
	High  int64
	Count int64
	State byte
}

type GroupMeta struct{
	Name  string
	Desc  string
	State byte
}

type GroupDB interface{
	AddGroups(src <- chan GroupMeta)
	AddGroup(group, descr string,state byte)
	Groups(prefix string,ptr *Group,cb func())
	Group(group string, ptr *Group) bool
	Numberate(groups []string, id string)
	GetArticleID(group string, num int64) string
	Erase(upto DayID)
}

<commit_msg>Update groupdb.go<commit_after>package groupdb

type DayID uint32

func MakeDayID(year, month, day int) DayID {
	return (DayID(year)<<16)|(DayID(month)<<8)|DayID(day)
}

func (d DayID) Date() (year int, month int, day int) {
	year = int((d>>16)&0xffff)
	month = int((d>>8)&0xff)
	day = int(d&0xff)
	return
}

type DayProvider func() DayID

type Group struct{
	Name  string
	Desc  string
	Low   int64
	High  int64
	Count int64
	State byte
}

type GroupMeta struct{
	Name  string
	Desc  string
	State byte
}

type GroupDB interface{
	// Adds a stream of groups, supplied using a channel. The stream MAY
	// supply groups, that do exist already in the Database, as AddGroups
	// is required to check each existing group, supplied through the channel.
	AddGroups(src <- chan GroupMeta)
	// Adds a group to the DB. The group MUST not exist already in the
	// Database as AddGroup is not required to check the existence of
	// the newsgroup.
	AddGroup(group, descr string,state byte)
	// Scans for all groups, that have the given prefix.
	// For every group, that has been read, the function cb is called.
	Groups(prefix string,ptr *Group,cb func())
	// Reads a single group and stores it in the supplied Group object.
	// Returns true if the group exists.
	Group(group string, ptr *Group) bool
	Numberate(groups []string, id string)
	GetArticleID(group string, num int64) string
	Erase(upto DayID)
}

<|endoftext|>