<commit_before>package version

import "fmt"

const (
	// VersionMajor is for an API incompatible changes
	VersionMajor = 5
	// VersionMinor is for functionality in a backwards-compatible manner
	VersionMinor = 16
	// VersionPatch is for backwards-compatible bug fixes
	VersionPatch = 1

	// VersionDev indicates development branch. Releases will be empty string.
	VersionDev = "-dev"
)

// Version is the specification version that the package types support.
var Version = fmt.Sprintf("%d.%d.%d%s", VersionMajor, VersionMinor, VersionPatch, VersionDev)
<commit_msg>v5.16.1<commit_after>package version

import "fmt"

const (
	// VersionMajor is for an API incompatible changes
	VersionMajor = 5
	// VersionMinor is for functionality in a backwards-compatible manner
	VersionMinor = 16
	// VersionPatch is for backwards-compatible bug fixes
	VersionPatch = 1

	// VersionDev indicates development branch. Releases will be empty string.
	VersionDev = ""
)

// Version is the specification version that the package types support.
var Version = fmt.Sprintf("%d.%d.%d%s", VersionMajor, VersionMinor, VersionPatch, VersionDev)
<|endoftext|>


<commit_before>package version

import (
	"fmt"
	"strings"
)

var (
	// The git commit that was compiled. These will be filled in by the
	// compiler.
	GitCommit   string
	GitDescribe string

	// The main version number that is being run at the moment.
	//
	// Version must conform to the format expected by github.com/hashicorp/go-version
	// for tests to work.
	Version = "1.1.0"

	// A pre-release marker for the version. If this is "" (empty string)
	// then it means that it is a final release. Otherwise, this is a pre-release
	// such as "dev" (in development), "beta", "rc1", etc.
	VersionPrerelease = "dev"
)

// GetHumanVersion composes the parts of the version in a way that's suitable
// for displaying to humans.
func GetHumanVersion() string {
	version := Version
	if GitDescribe != "" {
		version = GitDescribe
	}

	release := VersionPrerelease
	if GitDescribe == "" && release == "" {
		release = "dev"
	}
	if release != "" {
		version += fmt.Sprintf("-%s", release)
		if GitCommit != "" {
			version += fmt.Sprintf(" (%s)", GitCommit)
		}
	}

	// Strip off any single quotes added by the git information.
	return strings.Replace(version, "'", "", -1)
}
<commit_msg>Dont duplicate release versions in prereleases<commit_after>package version

import (
	"fmt"
	"strings"
)

var (
	// The git commit that was compiled. These will be filled in by the
	// compiler.
	GitCommit   string
	GitDescribe string

	// The main version number that is being run at the moment.
	//
	// Version must conform to the format expected by github.com/hashicorp/go-version
	// for tests to work.
	Version = "1.1.0"

	// A pre-release marker for the version. If this is "" (empty string)
	// then it means that it is a final release. Otherwise, this is a pre-release
	// such as "dev" (in development), "beta", "rc1", etc.
	VersionPrerelease = "dev"
)

// GetHumanVersion composes the parts of the version in a way that's suitable
// for displaying to humans.
func GetHumanVersion() string {
	version := Version
	if GitDescribe != "" {
		version = GitDescribe
	}

	release := VersionPrerelease
	if GitDescribe == "" && release == "" {
		release = "dev"
	}

	if release != "" {
		if !strings.HasSuffix(version, "-"+release) {
			// if we tagged a prerelease version then the release is in the version already
			version += fmt.Sprintf("-%s", release)
		}
		if GitCommit != "" {
			version += fmt.Sprintf(" (%s)", GitCommit)
		}
	}

	// Strip off any single quotes added by the git information.
	return strings.Replace(version, "'", "", -1)
}
<|endoftext|>


<commit_before>package supervisor

import (
	"fmt"
	"sync"
	"testing"
	"time"

	"golang.org/x/net/context"
)

func ExampleSupervisor() {
	var supervisor Supervisor

	svc := Simpleservice(1)
	supervisor.Add(&svc)

	ctx, _ := context.WithTimeout(context.Background(), 1*time.Second)
	supervisor.Serve(ctx)
}

func TestString(t *testing.T) {
	t.Parallel()

	const expected = "test"
	var supervisor Supervisor
	supervisor.Name = expected

	if got := fmt.Sprintf("%s", &supervisor); got != expected {
		t.Errorf("error getting supervisor name: %s", got)
	}

}

func TestSimple(t *testing.T) {
	t.Parallel()

	var supervisor Supervisor

	svc := Simpleservice(1)
	supervisor.Add(&svc)

	ctx, _ := context.WithTimeout(context.Background(), 1*time.Second)
	supervisor.Serve(ctx)
	countService(t, &supervisor)

}

func TestMultiple(t *testing.T) {
	t.Parallel()

	var supervisor Supervisor

	svc1 := Simpleservice(2)
	supervisor.Add(&svc1)
	svc2 := Simpleservice(3)
	supervisor.Add(&svc2)

	ctx, _ := context.WithTimeout(context.Background(), 1*time.Second)
	supervisor.Serve(ctx)
	countService(t, &supervisor)

}

func TestCascaded(t *testing.T) {
	t.Parallel()

	var supervisor Supervisor

	svc1 := Simpleservice(4)
	supervisor.Add(&svc1)
	svc2 := Simpleservice(5)
	supervisor.Add(&svc2)

	var childSupervisor Supervisor
	svc3 := Simpleservice(6)
	childSupervisor.Add(&svc3)
	svc4 := Simpleservice(7)
	childSupervisor.Add(&svc4)

	supervisor.Add(&childSupervisor)

	ctx, _ := context.WithTimeout(context.Background(), 1*time.Second)
	supervisor.Serve(ctx)
	countService(t, &supervisor)

}

func TestPanic(t *testing.T) {
	t.Parallel()

	var supervisor Supervisor
	supervisor.Backoff = 500 * time.Millisecond
	svc1 := panicservice(1)
	supervisor.Add(&svc1)

	ctx, _ := context.WithTimeout(context.Background(), 1*time.Second)
	supervisor.Serve(ctx)
	countService(t, &supervisor)

}

func TestFailing(t *testing.T) {
	t.Parallel()

	supervisor := Supervisor{
		Backoff: 1 * time.Second,
		Log: func(msg string) {
			t.Log("supervisor log:", msg)
		},
	}

	svc1 := failingservice(1)
	supervisor.Add(&svc1)

	ctx, _ := context.WithTimeout(context.Background(), 3*time.Second)
	supervisor.Serve(ctx)
	countService(t, &supervisor)

}

func TestAddServiceAfterServe(t *testing.T) {
	t.Parallel()

	var supervisor Supervisor

	svc1 := Simpleservice(1)
	supervisor.Add(&svc1)

	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
	done := make(chan struct{})
	go func() {
		supervisor.Serve(ctx)
		countService(t, &supervisor)
		done <- struct{}{}
	}()

	<-supervisor.startedServices
	svc2 := Simpleservice(2)
	supervisor.Add(&svc2)
	<-supervisor.startedServices

	cancel()
	<-ctx.Done()
	<-done

}

func TestRemoveServiceAfterServe(t *testing.T) {
	t.Parallel()

	var supervisor Supervisor

	svc1 := Simpleservice(1)
	supervisor.Add(&svc1)
	svc2 := Simpleservice(2)
	supervisor.Add(&svc2)

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	done := make(chan struct{})

	go func() {
		supervisor.Serve(ctx)
		countService(t, &supervisor)
		done <- struct{}{}
	}()

	lbefore := getServiceCount(&supervisor)
	supervisor.Remove("unknown service")
	lafter := getServiceCount(&supervisor)

	if lbefore != lafter {
		t.Error("the removal of an unknown service shouldn't happen")
	}

	<-supervisor.startedServices
	supervisor.Remove(svc1.String())

	lremoved := getServiceCount(&supervisor)
	if lbefore != lremoved {
		t.Error("the removal of a service should have affected the supervisor:", lbefore, lremoved)
	}

	cancel()
	<-ctx.Done()
	<-done

}

func TestServices(t *testing.T) {
	t.Parallel()

	var supervisor Supervisor

	svc1 := Simpleservice(1)
	supervisor.Add(&svc1)
	svc2 := Simpleservice(2)
	supervisor.Add(&svc2)

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	done := make(chan struct{})

	go func() {
		supervisor.Serve(ctx)
		done <- struct{}{}
	}()

	<-supervisor.startedServices
	svcs := supervisor.Services()
	for _, svcname := range []string{svc1.String(), svc2.String()} {
		if _, ok := svcs[svcname]; !ok {
			t.Errorf("expected service not found: %s", svcname)
		}
	}

	cancel()
	<-ctx.Done()
	<-done

}

func TestManualCancelation(t *testing.T) {
	t.Parallel()

	var supervisor Supervisor

	svc1 := Simpleservice(1)
	supervisor.Add(&svc1)
	svc2 := restartableservice{2, make(chan struct{})}
	supervisor.Add(&svc2)

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	done := make(chan struct{})

	go func() {
		supervisor.Serve(ctx)
		countService(t, &supervisor)
		done <- struct{}{}
	}()

	<-supervisor.startedServices
	<-svc2.restarted

	// Testing restart
	svcs := supervisor.Cancelations()
	svcancel := svcs[svc2.String()]
	svcancel()
	<-svc2.restarted

	cancel()
	<-ctx.Done()
	<-done

}

func TestServiceList(t *testing.T) {
	t.Parallel()

	var supervisor Supervisor

	svc1 := Simpleservice(1)
	supervisor.Add(&svc1)

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	done := make(chan struct{})

	go func() {
		supervisor.Serve(ctx)
		countService(t, &supervisor)
		done <- struct{}{}
	}()

	<-supervisor.startedServices

	svcs := supervisor.Services()
	if svc, ok := svcs[svc1.String()]; !ok || &svc1 != svc.(*Simpleservice) {
		t.Errorf("could not find service when listing them. %s missing", svc1.String())
	}

	cancel()
	<-ctx.Done()
	<-done

}

func TestDoubleStart(t *testing.T) {
	t.Parallel()

	var supervisor Supervisor

	var svc1 waitservice
	supervisor.Add(&svc1)

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	done := make(chan struct{})

	go func() {
		c := context.WithValue(ctx, "supervisor", 1)
		supervisor.Serve(c)
		countService(t, &supervisor)
		done <- struct{}{}
	}()
	go func() {
		c := context.WithValue(ctx, "supervisor", 2)
		supervisor.Serve(c)
	}()

	<-supervisor.startedServices

	cancel()
	<-ctx.Done()
	<-done

	svc1.mu.Lock()
	count := svc1.count
	supervisors := svc1.supervisors
	if count != 1 {
		t.Error("wait service should have been started once:", count, "supervisor IDs:", supervisors)
	}
	svc1.mu.Unlock()

}

func TestRestart(t *testing.T) {
	t.Parallel()

	var supervisor Supervisor

	var svc1 waitservice
	supervisor.Add(&svc1)

	for i := 0; i < 2; i++ {
		done := make(chan struct{})

		ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
		go func() {
			supervisor.Serve(ctx)
			countService(t, &supervisor)
			done <- struct{}{}
		}()
		<-supervisor.startedServices

		cancel()
		<-ctx.Done()
		<-done
	}

	if svc1.count != 2 {
		t.Error("wait service should have been started twice:", svc1.count)
	}

}

func TestFailingRestarts(t *testing.T) {
	t.Parallel()

	var supervisor Supervisor

	var svc1 defectiveservice
	supervisor.Add(&svc1)

	for i := 0; i < 2; i++ {
		done := make(chan struct{})

		ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
		go func() {
			supervisor.Serve(ctx)
			countService(t, &supervisor)
			done <- struct{}{}
		}()
		<-supervisor.startedServices

		cancel()
		<-ctx.Done()
		<-done
	}

	// should arrive here with no panic

}

type defectiveservice struct{}

func (s *defectiveservice) Serve(ctx context.Context) {
	<-ctx.Done()
}

func (s *defectiveservice) String() string {
	return fmt.Sprintf("defective service")
}

type failingservice int

func (s *failingservice) Serve(ctx context.Context) {
	select {
	case <-ctx.Done():
		return
	default:
		time.Sleep(100 * time.Millisecond)
		*s++
		return
	}
}

func (s *failingservice) String() string {
	return fmt.Sprintf("failing service %v", *s)
}

type panicservice int

func (s *panicservice) Serve(ctx context.Context) {
	for {
		select {
		case <-ctx.Done():
			return
		default:
			time.Sleep(100 * time.Millisecond)
			panic("forcing panic")
		}
	}
}

func (s *panicservice) String() string {
	return fmt.Sprintf("panic service %v", *s)
}

type restartableservice struct {
	id        int
	restarted chan struct{}
}

func (s *restartableservice) Serve(ctx context.Context) {
	var i int
	for {
		i++
		select {
		case <-ctx.Done():
			return
		default:
			time.Sleep(500 * time.Millisecond)
			select {
			case s.restarted <- struct{}{}:
			default:
			}
		}
	}
}

func (s *restartableservice) String() string {
	return fmt.Sprintf("restartable service %v", *s)
}

type Simpleservice int

func (s *Simpleservice) String() string {
	return fmt.Sprintf("simple service %d", int(*s))
}

func (s *Simpleservice) Serve(ctx context.Context) {
	var i int
	for {
		i++
		select {
		case <-ctx.Done():
			return
		default:
			time.Sleep(500 * time.Millisecond)
		}
	}
}

type waitservice struct {
	mu          sync.Mutex
	count       int
	supervisors []int
}

func (s *waitservice) Serve(ctx context.Context) {
	s.mu.Lock()
	s.count++
	id := ctx.Value("supervisor")
	if id != nil {
		s.supervisors = append(s.supervisors, id.(int))
	}
	s.mu.Unlock()
	<-ctx.Done()
}

func (s *waitservice) String() string {
	return fmt.Sprintf("wait service %v", s.count)
}

func countService(t *testing.T, s *Supervisor) {
	s.runningMu.Lock()
	r := s.running
	s.runningMu.Unlock()
	if r != 0 {
		t.Fatalf("not all services were stopped. possibly a bug: %d services left", r)
	}
}

func getServiceCount(s *Supervisor) int {
	s.servicesMu.Lock()
	l := len(s.services)
	s.servicesMu.Unlock()
	return l
}
<commit_msg>code grooming<commit_after>package supervisor

import (
	"fmt"
	"sync"
	"testing"
	"time"

	"golang.org/x/net/context"
)

func ExampleSupervisor() {
	var supervisor Supervisor

	svc := Simpleservice(1)
	supervisor.Add(&svc)

	ctx, _ := context.WithTimeout(context.Background(), 1*time.Second)
	supervisor.Serve(ctx)
}

func TestString(t *testing.T) {
	t.Parallel()

	const expected = "test"
	var supervisor Supervisor
	supervisor.Name = expected

	if got := fmt.Sprintf("%s", &supervisor); got != expected {
		t.Errorf("error getting supervisor name: %s", got)
	}
}

func TestSimple(t *testing.T) {
	t.Parallel()

	var supervisor Supervisor

	svc := Simpleservice(1)
	supervisor.Add(&svc)

	ctx, _ := context.WithTimeout(context.Background(), 1*time.Second)
	supervisor.Serve(ctx)
	countService(t, &supervisor)
}

func TestMultiple(t *testing.T) {
	t.Parallel()

	var supervisor Supervisor

	svc1 := Simpleservice(2)
	supervisor.Add(&svc1)
	svc2 := Simpleservice(3)
	supervisor.Add(&svc2)

	ctx, _ := context.WithTimeout(context.Background(), 1*time.Second)
	supervisor.Serve(ctx)
	countService(t, &supervisor)
}

func TestCascaded(t *testing.T) {
	t.Parallel()

	var supervisor Supervisor

	svc1 := Simpleservice(4)
	supervisor.Add(&svc1)
	svc2 := Simpleservice(5)
	supervisor.Add(&svc2)

	var childSupervisor Supervisor
	svc3 := Simpleservice(6)
	childSupervisor.Add(&svc3)
	svc4 := Simpleservice(7)
	childSupervisor.Add(&svc4)

	supervisor.Add(&childSupervisor)

	ctx, _ := context.WithTimeout(context.Background(), 1*time.Second)
	supervisor.Serve(ctx)
	countService(t, &supervisor)
}

func TestPanic(t *testing.T) {
	t.Parallel()

	var supervisor Supervisor
	supervisor.Backoff = 500 * time.Millisecond
	svc1 := panicservice(1)
	supervisor.Add(&svc1)

	ctx, _ := context.WithTimeout(context.Background(), 1*time.Second)
	supervisor.Serve(ctx)
	countService(t, &supervisor)
}

func TestFailing(t *testing.T) {
	t.Parallel()

	supervisor := Supervisor{
		Backoff: 1 * time.Second,
		Log: func(msg string) {
			t.Log("supervisor log:", msg)
		},
	}

	svc1 := failingservice(1)
	supervisor.Add(&svc1)

	ctx, _ := context.WithTimeout(context.Background(), 3*time.Second)
	supervisor.Serve(ctx)
	countService(t, &supervisor)
}

func TestAddServiceAfterServe(t *testing.T) {
	t.Parallel()

	var supervisor Supervisor

	svc1 := Simpleservice(1)
	supervisor.Add(&svc1)

	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		supervisor.Serve(ctx)
		countService(t, &supervisor)
		wg.Done()
	}()

	<-supervisor.startedServices
	svc2 := Simpleservice(2)
	supervisor.Add(&svc2)
	<-supervisor.startedServices

	cancel()
	<-ctx.Done()
	wg.Wait()
}

func TestRemoveServiceAfterServe(t *testing.T) {
	t.Parallel()

	var supervisor Supervisor

	svc1 := Simpleservice(1)
	supervisor.Add(&svc1)
	svc2 := Simpleservice(2)
	supervisor.Add(&svc2)

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		supervisor.Serve(ctx)
		countService(t, &supervisor)
		wg.Done()
	}()

	lbefore := getServiceCount(&supervisor)
	supervisor.Remove("unknown service")
	lafter := getServiceCount(&supervisor)

	if lbefore != lafter {
		t.Error("the removal of an unknown service shouldn't happen")
	}

	<-supervisor.startedServices
	supervisor.Remove(svc1.String())

	lremoved := getServiceCount(&supervisor)
	if lbefore != lremoved {
		t.Error("the removal of a service should have affected the supervisor:", lbefore, lremoved)
	}

	cancel()
	<-ctx.Done()
	wg.Wait()
}

func TestServices(t *testing.T) {
	t.Parallel()

	var supervisor Supervisor

	svc1 := Simpleservice(1)
	supervisor.Add(&svc1)
	svc2 := Simpleservice(2)
	supervisor.Add(&svc2)

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		supervisor.Serve(ctx)
	}()

	<-supervisor.startedServices
	svcs := supervisor.Services()
	for _, svcname := range []string{svc1.String(), svc2.String()} {
		if _, ok := svcs[svcname]; !ok {
			t.Errorf("expected service not found: %s", svcname)
		}
	}

	cancel()
	<-ctx.Done()
	wg.Done()
}

func TestManualCancelation(t *testing.T) {
	t.Parallel()

	var supervisor Supervisor

	svc1 := Simpleservice(1)
	supervisor.Add(&svc1)
	svc2 := restartableservice{2, make(chan struct{})}
	supervisor.Add(&svc2)

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		supervisor.Serve(ctx)
		countService(t, &supervisor)
	}()

	<-supervisor.startedServices
	<-svc2.restarted

	// Testing restart
	svcs := supervisor.Cancelations()
	svcancel := svcs[svc2.String()]
	svcancel()
	<-svc2.restarted

	cancel()
	<-ctx.Done()
	wg.Done()
}

func TestServiceList(t *testing.T) {
	t.Parallel()

	var supervisor Supervisor

	svc1 := Simpleservice(1)
	supervisor.Add(&svc1)

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		supervisor.Serve(ctx)
		countService(t, &supervisor)
	}()

	<-supervisor.startedServices

	svcs := supervisor.Services()
	if svc, ok := svcs[svc1.String()]; !ok || &svc1 != svc.(*Simpleservice) {
		t.Errorf("could not find service when listing them. %s missing", svc1.String())
	}

	cancel()
	<-ctx.Done()
	wg.Done()
}

func TestDoubleStart(t *testing.T) {
	t.Parallel()

	var supervisor Supervisor

	var svc1 waitservice
	supervisor.Add(&svc1)

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)

	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		c := context.WithValue(ctx, "supervisor", 1)
		supervisor.Serve(c)
		countService(t, &supervisor)
		wg.Done()
	}()
	<-supervisor.startedServices

	wg.Add(1)
	go func() {
		c := context.WithValue(ctx, "supervisor", 2)
		supervisor.Serve(c)
		countService(t, &supervisor)
		wg.Done()
	}()

	cancel()
	<-ctx.Done()
	wg.Wait()

	svc1.mu.Lock()
	count := svc1.count
	supervisors := svc1.supervisors
	if count != 1 {
		t.Error("wait service should have been started once:", count, "supervisor IDs:", supervisors)
	}
	svc1.mu.Unlock()
}

func TestRestart(t *testing.T) {
	t.Parallel()

	var supervisor Supervisor

	var svc1 waitservice
	supervisor.Add(&svc1)

	for i := 0; i < 2; i++ {
		var wg sync.WaitGroup
		wg.Add(1)

		ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
		go func() {
			supervisor.Serve(ctx)
			countService(t, &supervisor)
			wg.Done()
		}()
		<-supervisor.startedServices

		cancel()
		<-ctx.Done()
		wg.Wait()
	}

	if svc1.count != 2 {
		t.Error("wait service should have been started twice:", svc1.count)
	}

}

func TestFailingRestarts(t *testing.T) {
	t.Parallel()

	var supervisor Supervisor

	var svc1 defectiveservice
	supervisor.Add(&svc1)

	for i := 0; i < 2; i++ {
		var wg sync.WaitGroup
		wg.Add(1)

		ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
		go func() {
			supervisor.Serve(ctx)
			countService(t, &supervisor)
			wg.Done()
		}()
		<-supervisor.startedServices

		cancel()
		<-ctx.Done()
		wg.Wait()
	}

	// should arrive here with no panic

}

type defectiveservice struct{}

func (s *defectiveservice) Serve(ctx context.Context) {
	<-ctx.Done()
}

func (s *defectiveservice) String() string {
	return fmt.Sprintf("defective service")
}

type failingservice int

func (s *failingservice) Serve(ctx context.Context) {
	select {
	case <-ctx.Done():
		return
	default:
		time.Sleep(100 * time.Millisecond)
		*s++
		return
	}
}

func (s *failingservice) String() string {
	return fmt.Sprintf("failing service %v", *s)
}

type panicservice int

func (s *panicservice) Serve(ctx context.Context) {
	for {
		select {
		case <-ctx.Done():
			return
		default:
			time.Sleep(100 * time.Millisecond)
			panic("forcing panic")
		}
	}
}

func (s *panicservice) String() string {
	return fmt.Sprintf("panic service %v", *s)
}

type restartableservice struct {
	id        int
	restarted chan struct{}
}

func (s *restartableservice) Serve(ctx context.Context) {
	var i int
	for {
		i++
		select {
		case <-ctx.Done():
			return
		default:
			time.Sleep(500 * time.Millisecond)
			select {
			case s.restarted <- struct{}{}:
			default:
			}
		}
	}
}

func (s *restartableservice) String() string {
	return fmt.Sprintf("restartable service %v", *s)
}

type Simpleservice int

func (s *Simpleservice) String() string {
	return fmt.Sprintf("simple service %d", int(*s))
}

func (s *Simpleservice) Serve(ctx context.Context) {
	var i int
	for {
		i++
		select {
		case <-ctx.Done():
			return
		default:
			time.Sleep(500 * time.Millisecond)
		}
	}
}

type waitservice struct {
	mu          sync.Mutex
	count       int
	supervisors []int
}

func (s *waitservice) Serve(ctx context.Context) {
	s.mu.Lock()
	s.count++
	id := ctx.Value("supervisor")
	if id != nil {
		s.supervisors = append(s.supervisors, id.(int))
	}
	s.mu.Unlock()
	<-ctx.Done()
}

func (s *waitservice) String() string {
	return fmt.Sprintf("wait service %v", s.count)
}

func countService(t *testing.T, s *Supervisor) {
	s.runningMu.Lock()
	r := s.running
	s.runningMu.Unlock()
	if r != 0 {
		t.Fatalf("not all services were stopped. possibly a bug: %d services left", r)
	}
}

func getServiceCount(s *Supervisor) int {
	s.servicesMu.Lock()
	l := len(s.services)
	s.servicesMu.Unlock()
	return l
}
<|endoftext|>


<commit_before>package surveys

import (
	"encoding/json"
	"github.com/AreaHQ/jsonhal"
	"github.com/ONSdigital/go-launch-a-survey/settings"
	"log"
	"net/http"
	"regexp"
)

// LauncherSchema is a representation of a schema in the Launcher
type LauncherSchema struct {
	Name     string
	EqID     string
	FormType string
	URL      string
}

// RegisterResponse is the response from the eq-survey-register request
type RegisterResponse struct {
	jsonhal.Hal
}

// Schemas is a list of Schema
type Schemas []Schema

// Schema is an available schema
type Schema struct {
	jsonhal.Hal
	Name string `json:"name"`
}

var eqIDFormTypeRegex = regexp.MustCompile(`^(?P<eq_id>[a-z0-9]+)_(?P<form_type>\w+)`)

func extractEqIDFormType(schema string) (EqID, formType string) {
	match := eqIDFormTypeRegex.FindStringSubmatch(schema)
	if match != nil {
		EqID = match[1]
		formType = match[2]
	}
	return
}

// LauncherSchemaFromFilename creates a LauncherSchema record from a schema filename
func LauncherSchemaFromFilename(filename string) LauncherSchema {
	EqID, formType := extractEqIDFormType(filename)
	return LauncherSchema{
		Name:     filename,
		EqID:     EqID,
		FormType: formType,
	}
}

// GetAvailableSchemas Gets the list of static schemas an joins them with any schemas from the eq-survey-register if defined
func GetAvailableSchemas() []LauncherSchema {
	schemaList := []LauncherSchema{
		LauncherSchemaFromFilename("0_star_wars.json"),
		LauncherSchemaFromFilename("1_0005.json"),
		LauncherSchemaFromFilename("1_0102.json"),
		LauncherSchemaFromFilename("1_0112.json"),
		LauncherSchemaFromFilename("1_0203.json"),
		LauncherSchemaFromFilename("1_0205.json"),
		LauncherSchemaFromFilename("1_0213.json"),
		LauncherSchemaFromFilename("1_0215.json"),
		LauncherSchemaFromFilename("2_0001.json"),
		LauncherSchemaFromFilename("census_communal.json"),
		LauncherSchemaFromFilename("census_household.json"),
		LauncherSchemaFromFilename("census_individual.json"),
		LauncherSchemaFromFilename("e_commerce.json"),
		LauncherSchemaFromFilename("mbs_0111.json"),
		LauncherSchemaFromFilename("multiple_answers.json"),
		LauncherSchemaFromFilename("test_big_list_naughty_strings.json"),
		LauncherSchemaFromFilename("test_checkbox.json"),
		LauncherSchemaFromFilename("test_conditional_dates.json"),
		LauncherSchemaFromFilename("test_conditional_routing.json"),
		LauncherSchemaFromFilename("test_currency.json"),
		LauncherSchemaFromFilename("test_dates.json"),
		LauncherSchemaFromFilename("test_dropdown_mandatory.json"),
		LauncherSchemaFromFilename("test_dropdown_mandatory_with_overridden_error.json"),
		LauncherSchemaFromFilename("test_dropdown_optional.json"),
		LauncherSchemaFromFilename("test_error_messages.json"),
		LauncherSchemaFromFilename("test_final_confirmation.json"),
		LauncherSchemaFromFilename("test_household_question.json"),
		LauncherSchemaFromFilename("test_interstitial_page.json"),
		LauncherSchemaFromFilename("test_introduction.json"),
		LauncherSchemaFromFilename("test_language.json"),
		LauncherSchemaFromFilename("test_language_cy.json"),
		LauncherSchemaFromFilename("test_markup.json"),
		LauncherSchemaFromFilename("test_metadata_routing.json"),
		LauncherSchemaFromFilename("test_multiple_piping.json"),
		LauncherSchemaFromFilename("test_navigation.json"),
		LauncherSchemaFromFilename("test_navigation_completeness.json"),
		LauncherSchemaFromFilename("test_navigation_confirmation.json"),
		LauncherSchemaFromFilename("test_navigation_routing.json"),
		LauncherSchemaFromFilename("test_numbers.json"),
		LauncherSchemaFromFilename("test_percentage.json"),
		LauncherSchemaFromFilename("test_question_guidance.json"),
		LauncherSchemaFromFilename("test_radio_checkbox_descriptions.json"),
		LauncherSchemaFromFilename("test_radio_mandatory.json"),
		LauncherSchemaFromFilename("test_radio_mandatory_with_mandatory_other.json"),
		LauncherSchemaFromFilename("test_radio_mandatory_with_mandatory_other_overridden_error.json"),
		LauncherSchemaFromFilename("test_radio_mandatory_with_optional_other.json"),
		LauncherSchemaFromFilename("test_radio_mandatory_with_overridden_error.json"),
		LauncherSchemaFromFilename("test_radio_optional.json"),
		LauncherSchemaFromFilename("test_radio_optional_with_mandatory_other.json"),
		LauncherSchemaFromFilename("test_radio_optional_with_mandatory_other_overridden_error.json"),
		LauncherSchemaFromFilename("test_radio_optional_with_optional_other.json"),
		LauncherSchemaFromFilename("test_relationship_household.json"),
		LauncherSchemaFromFilename("test_repeating_and_conditional_routing.json"),
		LauncherSchemaFromFilename("test_repeating_household.json"),
		LauncherSchemaFromFilename("test_routing_date_equals.json"),
		LauncherSchemaFromFilename("test_routing_date_greater_than.json"),
		LauncherSchemaFromFilename("test_routing_date_less_than.json"),
		LauncherSchemaFromFilename("test_routing_date_not_equals.json"),
		LauncherSchemaFromFilename("test_routing_group.json"),
		LauncherSchemaFromFilename("test_routing_number_equals.json"),
		LauncherSchemaFromFilename("test_routing_number_greater_than.json"),
		LauncherSchemaFromFilename("test_routing_number_greater_than_or_equal.json"),
		LauncherSchemaFromFilename("test_routing_number_less_than.json"),
		LauncherSchemaFromFilename("test_routing_number_less_than_or_equal.json"),
		LauncherSchemaFromFilename("test_routing_number_not_equals.json"),
		LauncherSchemaFromFilename("test_routing_on_multiple_select.json"),
		LauncherSchemaFromFilename("test_skip_condition.json"),
		LauncherSchemaFromFilename("test_skip_condition_block.json"),
		LauncherSchemaFromFilename("test_skip_condition_group.json"),
		LauncherSchemaFromFilename("test_summary.json"),
		LauncherSchemaFromFilename("test_section_summary.json"),
		LauncherSchemaFromFilename("test_sum_equal_validation_against_total.json"),
		LauncherSchemaFromFilename("test_sum_equal_or_less_validation_against_total.json"),
		LauncherSchemaFromFilename("test_sum_less_validation_against_total.json"),
		LauncherSchemaFromFilename("test_view_submitted_response.json"),
		LauncherSchemaFromFilename("test_textarea.json"),
		LauncherSchemaFromFilename("test_textfield.json"),
		LauncherSchemaFromFilename("test_timeout.json"),
		LauncherSchemaFromFilename("test_total_breakdown.json"),
		LauncherSchemaFromFilename("test_unit_patterns.json"),
	}

	return append(schemaList, getAvailableSchemasFromRegister()...)
}

func getAvailableSchemasFromRegister() []LauncherSchema {

	schemaList := []LauncherSchema{}

	if settings.Get("SURVEY_REGISTER_URL") != "" {
		req, err := http.NewRequest("GET", settings.Get("SURVEY_REGISTER_URL"), nil)
		if err != nil {
			log.Fatal("NewRequest: ", err)
			return []LauncherSchema{}
		}
		client := &http.Client{}

		resp, err := client.Do(req)
		if err != nil {
			log.Fatal("Do: ", err)
			return []LauncherSchema{}
		}

		defer resp.Body.Close()

		var registerResponse RegisterResponse

		if err := json.NewDecoder(resp.Body).Decode(&registerResponse); err != nil {
			log.Println(err)
		}

		var schemas Schemas

		schemasJSON, _ := json.Marshal(registerResponse.Embedded["schemas"])

		if err := json.Unmarshal(schemasJSON, &schemas); err != nil {
			log.Println(err)
		}

		for _, schema := range schemas {
			url := schema.Links["self"]
			EqID, formType := extractEqIDFormType(schema.Name)
			schemaList = append(schemaList, LauncherSchema{
				Name:     schema.Name,
				URL:      url.Href,
				EqID:     EqID,
				FormType: formType,
			})
		}
	}

	return schemaList
}

// FindSurveyByName Finds the schema in the list of available schemas
func FindSurveyByName(name string) LauncherSchema {
	for _, survey := range GetAvailableSchemas() {
		if survey.Name == name {
			return survey
		}
	}
	panic("Survey not found")
}
<commit_msg>Add test_default schema<commit_after>package surveys

import (
	"encoding/json"
	"github.com/AreaHQ/jsonhal"
	"github.com/ONSdigital/go-launch-a-survey/settings"
	"log"
	"net/http"
	"regexp"
)

// LauncherSchema is a representation of a schema in the Launcher
type LauncherSchema struct {
	Name     string
	EqID     string
	FormType string
	URL      string
}

// RegisterResponse is the response from the eq-survey-register request
type RegisterResponse struct {
	jsonhal.Hal
}

// Schemas is a list of Schema
type Schemas []Schema

// Schema is an available schema
type Schema struct {
	jsonhal.Hal
	Name string `json:"name"`
}

var eqIDFormTypeRegex = regexp.MustCompile(`^(?P<eq_id>[a-z0-9]+)_(?P<form_type>\w+)`)

func extractEqIDFormType(schema string) (EqID, formType string) {
	match := eqIDFormTypeRegex.FindStringSubmatch(schema)
	if match != nil {
		EqID = match[1]
		formType = match[2]
	}
	return
}

// LauncherSchemaFromFilename creates a LauncherSchema record from a schema filename
func LauncherSchemaFromFilename(filename string) LauncherSchema {
	EqID, formType := extractEqIDFormType(filename)
	return LauncherSchema{
		Name:     filename,
		EqID:     EqID,
		FormType: formType,
	}
}

// GetAvailableSchemas Gets the list of static schemas an joins them with any schemas from the eq-survey-register if defined
func GetAvailableSchemas() []LauncherSchema {
	schemaList := []LauncherSchema{
		LauncherSchemaFromFilename("0_star_wars.json"),
		LauncherSchemaFromFilename("1_0005.json"),
		LauncherSchemaFromFilename("1_0102.json"),
		LauncherSchemaFromFilename("1_0112.json"),
		LauncherSchemaFromFilename("1_0203.json"),
		LauncherSchemaFromFilename("1_0205.json"),
		LauncherSchemaFromFilename("1_0213.json"),
		LauncherSchemaFromFilename("1_0215.json"),
		LauncherSchemaFromFilename("2_0001.json"),
		LauncherSchemaFromFilename("census_communal.json"),
		LauncherSchemaFromFilename("census_household.json"),
		LauncherSchemaFromFilename("census_individual.json"),
		LauncherSchemaFromFilename("e_commerce.json"),
		LauncherSchemaFromFilename("mbs_0111.json"),
		LauncherSchemaFromFilename("multiple_answers.json"),
		LauncherSchemaFromFilename("test_big_list_naughty_strings.json"),
		LauncherSchemaFromFilename("test_checkbox.json"),
		LauncherSchemaFromFilename("test_conditional_dates.json"),
		LauncherSchemaFromFilename("test_conditional_routing.json"),
		LauncherSchemaFromFilename("test_currency.json"),
		LauncherSchemaFromFilename("test_dates.json"),
		LauncherSchemaFromFilename("test_default.json"),
		LauncherSchemaFromFilename("test_dropdown_mandatory.json"),
		LauncherSchemaFromFilename("test_dropdown_mandatory_with_overridden_error.json"),
		LauncherSchemaFromFilename("test_dropdown_optional.json"),
		LauncherSchemaFromFilename("test_error_messages.json"),
		LauncherSchemaFromFilename("test_final_confirmation.json"),
		LauncherSchemaFromFilename("test_household_question.json"),
		LauncherSchemaFromFilename("test_interstitial_page.json"),
		LauncherSchemaFromFilename("test_introduction.json"),
		LauncherSchemaFromFilename("test_language.json"),
		LauncherSchemaFromFilename("test_language_cy.json"),
		LauncherSchemaFromFilename("test_markup.json"),
		LauncherSchemaFromFilename("test_metadata_routing.json"),
		LauncherSchemaFromFilename("test_multiple_piping.json"),
		LauncherSchemaFromFilename("test_navigation.json"),
		LauncherSchemaFromFilename("test_navigation_completeness.json"),
		LauncherSchemaFromFilename("test_navigation_confirmation.json"),
		LauncherSchemaFromFilename("test_navigation_routing.json"),
		LauncherSchemaFromFilename("test_numbers.json"),
		LauncherSchemaFromFilename("test_percentage.json"),
		LauncherSchemaFromFilename("test_question_guidance.json"),
		LauncherSchemaFromFilename("test_radio_checkbox_descriptions.json"),
		LauncherSchemaFromFilename("test_radio_mandatory.json"),
		LauncherSchemaFromFilename("test_radio_mandatory_with_mandatory_other.json"),
		LauncherSchemaFromFilename("test_radio_mandatory_with_mandatory_other_overridden_error.json"),
		LauncherSchemaFromFilename("test_radio_mandatory_with_optional_other.json"),
		LauncherSchemaFromFilename("test_radio_mandatory_with_overridden_error.json"),
		LauncherSchemaFromFilename("test_radio_optional.json"),
		LauncherSchemaFromFilename("test_radio_optional_with_mandatory_other.json"),
		LauncherSchemaFromFilename("test_radio_optional_with_mandatory_other_overridden_error.json"),
		LauncherSchemaFromFilename("test_radio_optional_with_optional_other.json"),
		LauncherSchemaFromFilename("test_relationship_household.json"),
		LauncherSchemaFromFilename("test_repeating_and_conditional_routing.json"),
		LauncherSchemaFromFilename("test_repeating_household.json"),
		LauncherSchemaFromFilename("test_routing_date_equals.json"),
		LauncherSchemaFromFilename("test_routing_date_greater_than.json"),
		LauncherSchemaFromFilename("test_routing_date_less_than.json"),
		LauncherSchemaFromFilename("test_routing_date_not_equals.json"),
		LauncherSchemaFromFilename("test_routing_group.json"),
		LauncherSchemaFromFilename("test_routing_number_equals.json"),
		LauncherSchemaFromFilename("test_routing_number_greater_than.json"),
		LauncherSchemaFromFilename("test_routing_number_greater_than_or_equal.json"),
		LauncherSchemaFromFilename("test_routing_number_less_than.json"),
		LauncherSchemaFromFilename("test_routing_number_less_than_or_equal.json"),
		LauncherSchemaFromFilename("test_routing_number_not_equals.json"),
		LauncherSchemaFromFilename("test_routing_on_multiple_select.json"),
		LauncherSchemaFromFilename("test_skip_condition.json"),
		LauncherSchemaFromFilename("test_skip_condition_block.json"),
		LauncherSchemaFromFilename("test_skip_condition_group.json"),
		LauncherSchemaFromFilename("test_summary.json"),
		LauncherSchemaFromFilename("test_section_summary.json"),
		LauncherSchemaFromFilename("test_sum_equal_validation_against_total.json"),
		LauncherSchemaFromFilename("test_sum_equal_or_less_validation_against_total.json"),
		LauncherSchemaFromFilename("test_sum_less_validation_against_total.json"),
		LauncherSchemaFromFilename("test_view_submitted_response.json"),
		LauncherSchemaFromFilename("test_textarea.json"),
		LauncherSchemaFromFilename("test_textfield.json"),
		LauncherSchemaFromFilename("test_timeout.json"),
		LauncherSchemaFromFilename("test_total_breakdown.json"),
		LauncherSchemaFromFilename("test_unit_patterns.json"),
	}

	return append(schemaList, getAvailableSchemasFromRegister()...)
}

func getAvailableSchemasFromRegister() []LauncherSchema {

	schemaList := []LauncherSchema{}

	if settings.Get("SURVEY_REGISTER_URL") != "" {
		req, err := http.NewRequest("GET", settings.Get("SURVEY_REGISTER_URL"), nil)
		if err != nil {
			log.Fatal("NewRequest: ", err)
			return []LauncherSchema{}
		}
		client := &http.Client{}

		resp, err := client.Do(req)
		if err != nil {
			log.Fatal("Do: ", err)
			return []LauncherSchema{}
		}

		defer resp.Body.Close()

		var registerResponse RegisterResponse

		if err := json.NewDecoder(resp.Body).Decode(&registerResponse); err != nil {
			log.Println(err)
		}

		var schemas Schemas

		schemasJSON, _ := json.Marshal(registerResponse.Embedded["schemas"])

		if err := json.Unmarshal(schemasJSON, &schemas); err != nil {
			log.Println(err)
		}

		for _, schema := range schemas {
			url := schema.Links["self"]
			EqID, formType := extractEqIDFormType(schema.Name)
			schemaList = append(schemaList, LauncherSchema{
				Name:     schema.Name,
				URL:      url.Href,
				EqID:     EqID,
				FormType: formType,
			})
		}
	}

	return schemaList
}

// FindSurveyByName Finds the schema in the list of available schemas
func FindSurveyByName(name string) LauncherSchema {
	for _, survey := range GetAvailableSchemas() {
		if survey.Name == name {
			return survey
		}
	}
	panic("Survey not found")
}
<|endoftext|>


<commit_before>package viewer

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"os"
	"path/filepath"
	"strings"
	"testing"
)

const (
	DefaultAppName = "nagome"
)

type WriteNoClose struct {
	io.Writer
}

func (wnc *WriteNoClose) Close() error {
	return nil
}

func NewDiscardWithoutClose() io.WriteCloser {
	return &WriteNoClose{ioutil.Discard}
}

type ReadNoClose struct {
	io.Reader
}

func (wnc *ReadNoClose) Close() error {
	return nil
}

func makeTestCLI(savePath string) *CLI {
	c := &CLI{
		AppName:   DefaultAppName,
		SavePath:  savePath,
		OutStream: NewDiscardWithoutClose(),
	}

	logFlags := log.Lshortfile
	if testing.Verbose() {
		c.ErrStream = os.Stderr
	} else {
		c.ErrStream = NewDiscardWithoutClose()
	}
	c.log = log.New(c.ErrStream, "        ", logFlags)
	return c
}

func TestCLIVersion(t *testing.T) {
	savepath, err := ioutil.TempDir("", DefaultAppName)
	if err != nil {
		t.Fatal(err)
	}
	defer func() {
		err := os.RemoveAll(savepath)
		if err != nil {
			t.Fatal(err)
		}
	}()

	cli := makeTestCLI(savepath)

	rt := cli.RunCli([]string{DefaultAppName, "-v", "-dbgtostd"})
	if rt != 0 {
		t.Fatalf("Return value should be %v but %v", 0, rt)
	}
}

func TestCLIQuit(t *testing.T) {
	savepath, err := ioutil.TempDir("", DefaultAppName)
	if err != nil {
		t.Fatal(err)
	}
	defer func() {
		err := os.RemoveAll(savepath)
		if err != nil {
			t.Fatal(err)
		}
	}()

	cli := makeTestCLI(savepath)
	cli.InStream = &ReadNoClose{strings.NewReader("")}

	rt := cli.RunCli([]string{DefaultAppName, "-savepath", savepath, "-dbgtostd"})
	if rt != 0 {
		t.Fatalf("Return value should be %v but %v", 0, rt)
	}
}

func TestTCPAPI(t *testing.T) {
	var err error
	cli := NewCLI("test", "nagome")
	cli.SavePath, err = ioutil.TempDir("", "nagome")
	if err != nil {
		t.Fatal(err)
	}
	if err := os.MkdirAll(filepath.Join(cli.SavePath, pluginDirName), 0777); err != nil {
		t.Fatal(err)
	}
	defer func() {
		err := os.RemoveAll(cli.SavePath)
		if err != nil {
			t.Fatal(err)
		}
	}()
	cv := NewCommentViewer("", cli)

	plug := newPlugin(cv)
	plug.Name = "main"
	plug.Description = "main plugin"
	plug.Version = "0.0"
	plug.Method = "tcp"
	plug.Subscribe = []string{DomainNagome, DomainComment, DomainUI}
	cv.AddPlugin(plug)

	cv.TCPPort = "0"

	cv.Start()

	conn, err := net.Dial("tcp", ":"+cv.TCPPort)
	if err != nil {
		t.Fatal(err)
	}

	// Connect as a main plugin
	fmt.Fprintf(conn, "{ \"domain\": \"nagome_direct\", \"command\": \"No\", \"content\": { \"no\": 0 } }\n")

	dec := json.NewDecoder(conn)
	m := new(Message)
	for {
		err := dec.Decode(m)
		if err != nil {
			t.Fatal("Should be accepted : ", err)
		}
		if m.Domain == DomainDirectngm && m.Command == CommDirectngmPlugEnabled {
			break
		}
	}

	err = conn.Close()
	if err != nil {
		t.Fatal(err)
	}
	cv.Wait()
	// shold quit because main plugin was closed
}
<commit_msg>[fix] test is not passed when port is busy<commit_after>package viewer

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"os"
	"path/filepath"
	"strings"
	"testing"
)

const (
	DefaultAppName = "nagome"
)

type WriteNoClose struct {
	io.Writer
}

func (wnc *WriteNoClose) Close() error {
	return nil
}

func NewDiscardWithoutClose() io.WriteCloser {
	return &WriteNoClose{ioutil.Discard}
}

type ReadNoClose struct {
	io.Reader
}

func (wnc *ReadNoClose) Close() error {
	return nil
}

func makeTestCLI(savePath string) *CLI {
	c := &CLI{
		AppName:   DefaultAppName,
		SavePath:  savePath,
		OutStream: NewDiscardWithoutClose(),
	}

	logFlags := log.Lshortfile
	if testing.Verbose() {
		c.ErrStream = os.Stderr
	} else {
		c.ErrStream = NewDiscardWithoutClose()
	}
	c.log = log.New(c.ErrStream, "        ", logFlags)
	return c
}

func TestCLIVersion(t *testing.T) {
	savepath, err := ioutil.TempDir("", DefaultAppName)
	if err != nil {
		t.Fatal(err)
	}
	defer func() {
		err := os.RemoveAll(savepath)
		if err != nil {
			t.Fatal(err)
		}
	}()

	cli := makeTestCLI(savepath)

	rt := cli.RunCli([]string{DefaultAppName, "-v", "-dbgtostd"})
	if rt != 0 {
		t.Fatalf("Return value should be %v but %v", 0, rt)
	}
}

func TestCLIQuit(t *testing.T) {
	savepath, err := ioutil.TempDir("", DefaultAppName)
	if err != nil {
		t.Fatal(err)
	}
	defer func() {
		err := os.RemoveAll(savepath)
		if err != nil {
			t.Fatal(err)
		}
	}()

	cli := makeTestCLI(savepath)
	cli.InStream = &ReadNoClose{strings.NewReader("")}

	rt := cli.RunCli([]string{DefaultAppName, "-savepath", savepath, "-dbgtostd", "-p", "0"})
	if rt != 0 {
		t.Fatalf("Return value should be %v but %v", 0, rt)
	}
}

func TestTCPAPI(t *testing.T) {
	var err error
	cli := NewCLI("test", "nagome")
	cli.SavePath, err = ioutil.TempDir("", "nagome")
	if err != nil {
		t.Fatal(err)
	}
	if err := os.MkdirAll(filepath.Join(cli.SavePath, pluginDirName), 0777); err != nil {
		t.Fatal(err)
	}
	defer func() {
		err := os.RemoveAll(cli.SavePath)
		if err != nil {
			t.Fatal(err)
		}
	}()
	cv := NewCommentViewer("", cli)

	plug := newPlugin(cv)
	plug.Name = "main"
	plug.Description = "main plugin"
	plug.Version = "0.0"
	plug.Method = "tcp"
	plug.Subscribe = []string{DomainNagome, DomainComment, DomainUI}
	cv.AddPlugin(plug)

	cv.TCPPort = "0"

	cv.Start()

	conn, err := net.Dial("tcp", ":"+cv.TCPPort)
	if err != nil {
		t.Fatal(err)
	}

	// Connect as a main plugin
	fmt.Fprintf(conn, "{ \"domain\": \"nagome_direct\", \"command\": \"No\", \"content\": { \"no\": 0 } }\n")

	dec := json.NewDecoder(conn)
	m := new(Message)
	for {
		err := dec.Decode(m)
		if err != nil {
			t.Fatal("Should be accepted : ", err)
		}
		if m.Domain == DomainDirectngm && m.Command == CommDirectngmPlugEnabled {
			break
		}
	}

	err = conn.Close()
	if err != nil {
		t.Fatal(err)
	}
	cv.Wait()
	// shold quit because main plugin was closed
}
<|endoftext|>


<commit_before>package queue_test

import (
	. "github.com/alphagov/govuk_crawler_worker/queue"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"net/url"

	"github.com/alphagov/govuk_crawler_worker/util"
	"github.com/streadway/amqp"
)

var _ = Describe("QueueConnection", func() {
	amqpAddr := util.GetEnvDefault("AMQP_ADDRESS", "amqp://guest:guest@localhost:5672/")

	It("fails if it can't connect to an AMQP server", func() {
		connection, err := NewQueueConnection("amqp://guest:guest@localhost:50000/")

		Expect(err).ToNot(BeNil())
		Expect(connection).To(BeNil())
	})

	Describe("Connection errors", func() {
		var (
			connection *QueueConnection
			proxy      *util.ProxyTCP
			proxyAddr  string           = "localhost:5673"
			queueName  string           = "govuk_crawler_worker-test-crawler-queue"
			fatalErrs  chan *amqp.Error = make(chan *amqp.Error)
		)

		BeforeEach(func() {
			proxyDest, err := addrFromURL(amqpAddr)
			Expect(err).To(BeNil())
			proxyURL, err := urlChangeAddr(amqpAddr, proxyAddr)
			Expect(err).To(BeNil())

			proxy, err = util.NewProxyTCP(proxyAddr, proxyDest)
			Expect(err).To(BeNil())
			Expect(proxy).ToNot(BeNil())

			connection, err = NewQueueConnection(proxyURL)
			Expect(err).To(BeNil())
			Expect(connection).ToNot(BeNil())

			connection.HandleFatalError = func(err *amqp.Error) {
				fatalErrs <- err
			}

			connection.HandleChannelClose = func(_ string) {}

			_, err = connection.QueueDeclare(queueName)
			Expect(err).To(BeNil())
		})

		AfterEach(func() {
			defer connection.Close()
			defer proxy.Close()

			// Assume existing connection is dead.
			connection.Close()
			connection, _ = NewQueueConnection(amqpAddr)

			deleted, err := connection.Channel.QueueDelete(queueName, false, false, false)
			Expect(err).To(BeNil())
			Expect(deleted).To(Equal(0))
		})

		It("should exit on non-recoverable errors", func(done Done) {
			const expectedError = "Exception \\(501\\) Reason: \"EOF\"|connection reset by peer"

			proxy.KillConnected()

			_, err := connection.Channel.QueueInspect(queueName)
			Expect(err.Error()).To(MatchRegexp(expectedError))

			// We'd normally log.Fatalln() here to exit.
			amqpErr := <-fatalErrs
			Expect(amqpErr.Error()).To(MatchRegexp(expectedError))
			Expect(amqpErr.Recover).To(Equal(false))

			// Connection no longer works.
			_, err = connection.Channel.QueueInspect(queueName)
			Expect(err).To(Equal(amqp.ErrClosed))

			close(done)
		})
	})

	Describe("Connecting to a running AMQP service", func() {
		var (
			connection    *QueueConnection
			connectionErr error
		)

		BeforeEach(func() {
			connection, connectionErr = NewQueueConnection(amqpAddr)
			connection.HandleChannelClose = func(_ string) {}
		})

		AfterEach(func() {
			defer connection.Close()
		})

		It("successfully connects to an AMQP service", func() {
			Expect(connectionErr).To(BeNil())
			Expect(connection).ToNot(BeNil())
		})

		It("can close the connection without errors", func() {
			Expect(connection.Close()).To(BeNil())
		})

		It("can declare an exchange", func() {
			var err error
			exchange := "govuk_crawler_worker-some-exchange"

			err = connection.ExchangeDeclare(exchange, "direct")
			Expect(err).To(BeNil())

			err = connection.Channel.ExchangeDelete(exchange, false, false)
			Expect(err).To(BeNil())
		})

		It("can declare a queue", func() {
			var (
				err   error
				queue amqp.Queue
				name  = "govuk_crawler_worker-some-queue"
			)

			queue, err = connection.QueueDeclare(name)
			Expect(err).To(BeNil())
			Expect(queue.Name).To(Equal(name))

			deleted, err := connection.Channel.QueueDelete(name, false, false, false)
			Expect(err).To(BeNil())
			Expect(deleted).To(Equal(0))
		})

		It("can bind a queue to an exchange", func() {
			var err error

			exchangeName := "govuk_crawler_worker-some-binding-exchange"
			queueName := "govuk_crawler_worker-some-binding-queue"

			err = connection.ExchangeDeclare(exchangeName, "direct")
			Expect(err).To(BeNil())

			_, err = connection.QueueDeclare(queueName)
			Expect(err).To(BeNil())

			err = connection.BindQueueToExchange(queueName, exchangeName)
			Expect(err).To(BeNil())

			deleted, err := connection.Channel.QueueDelete(queueName, false, false, false)
			Expect(err).To(BeNil())
			Expect(deleted).To(Equal(0))

			err = connection.Channel.ExchangeDelete(exchangeName, false, false)
			Expect(err).To(BeNil())
		})
	})

	Describe("working with messages on the queue", func() {
		var (
			publisher *QueueConnection
			consumer  *QueueConnection
			err       error
		)

		exchangeName := "govuk_crawler_worker-test-crawler-exchange"
		queueName := "govuk_crawler_worker-test-crawler-queue"

		BeforeEach(func() {
			publisher, err = NewQueueConnection(amqpAddr)
			Expect(err).To(BeNil())
			Expect(publisher).ToNot(BeNil())

			consumer, err = NewQueueConnection(amqpAddr)
			Expect(err).To(BeNil())
			Expect(consumer).ToNot(BeNil())

			publisher.HandleChannelClose = func(_ string) {}
			consumer.HandleChannelClose = func(_ string) {}
		})

		AfterEach(func() {
			// Consumer must Cancel() or Close() before deleting.
			consumer.Close()
			defer publisher.Close()

			deleted, err := publisher.Channel.QueueDelete(queueName, false, false, false)
			Expect(err).To(BeNil())
			Expect(deleted).To(Equal(0))

			err = publisher.Channel.ExchangeDelete(exchangeName, false, false)
			Expect(err).To(BeNil())
		})

		It("should consume and publish messages onto the provided queue and exchange", func(done Done) {
			err = consumer.ExchangeDeclare(exchangeName, "direct")
			Expect(err).To(BeNil())

			_, err = consumer.QueueDeclare(queueName)
			Expect(err).To(BeNil())

			err = consumer.BindQueueToExchange(queueName, exchangeName)
			Expect(err).To(BeNil())

			deliveries, err := consumer.Consume(queueName)
			Expect(err).To(BeNil())

			err = publisher.Publish(exchangeName, "#", "text/plain", "foo")
			Expect(err).To(BeNil())

			item := <-deliveries
			Expect(string(item.Body)).To(Equal("foo"))
			item.Ack(false)
			close(done)
		})
	})
})

// addrFromURL extracts the addr (host:port) from a URL string.
func addrFromURL(URL string) (string, error) {
	parsedURL, err := url.Parse(URL)
	if err != nil {
		return "", err
	}

	return parsedURL.Host, nil
}

// urlChangeAddr changes the addr (host:port) of a URL string.
func urlChangeAddr(origURL, newHost string) (string, error) {
	parsedURL, err := url.Parse(origURL)
	if err != nil {
		return "", err
	}

	parsedURL.Host = newHost
	return parsedURL.String(), nil
}
<commit_msg>Test we call HandleChannelClose()<commit_after>package queue_test

import (
	. "github.com/alphagov/govuk_crawler_worker/queue"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"net/url"

	"github.com/alphagov/govuk_crawler_worker/util"
	"github.com/streadway/amqp"
)

var _ = Describe("QueueConnection", func() {
	amqpAddr := util.GetEnvDefault("AMQP_ADDRESS", "amqp://guest:guest@localhost:5672/")

	It("fails if it can't connect to an AMQP server", func() {
		connection, err := NewQueueConnection("amqp://guest:guest@localhost:50000/")

		Expect(err).ToNot(BeNil())
		Expect(connection).To(BeNil())
	})

	Describe("Connection errors", func() {
		var (
			connection *QueueConnection
			proxy      *util.ProxyTCP
			proxyAddr  string           = "localhost:5673"
			queueName  string           = "govuk_crawler_worker-test-crawler-queue"
			fatalErrs  chan *amqp.Error = make(chan *amqp.Error)
			channelCloseMsgs chan string      = make(chan string)
		)

		BeforeEach(func() {
			proxyDest, err := addrFromURL(amqpAddr)
			Expect(err).To(BeNil())
			proxyURL, err := urlChangeAddr(amqpAddr, proxyAddr)
			Expect(err).To(BeNil())

			proxy, err = util.NewProxyTCP(proxyAddr, proxyDest)
			Expect(err).To(BeNil())
			Expect(proxy).ToNot(BeNil())

			connection, err = NewQueueConnection(proxyURL)
			Expect(err).To(BeNil())
			Expect(connection).ToNot(BeNil())

			connection.HandleFatalError = func(err *amqp.Error) {
				fatalErrs <- err
			}

			connection.HandleChannelClose = func(message string) {
				channelCloseMsgs <- message
			}

			_, err = connection.QueueDeclare(queueName)
			Expect(err).To(BeNil())
		})

		AfterEach(func() {
			defer connection.Close()
			defer proxy.Close()

			// Assume existing connection is dead.
			connection.Close()
			connection, _ = NewQueueConnection(amqpAddr)

			deleted, err := connection.Channel.QueueDelete(queueName, false, false, false)
			Expect(err).To(BeNil())
			Expect(deleted).To(Equal(0))
		})

		It("should call connection.HandleChannelClose() on recoverable errors", func(done Done) {
			connection.Channel.Close()

			// check connection.HandleChannelClose is called
			message := <-channelCloseMsgs
			Expect(message).To(Equal("Channel closed"))

			// Connection no longer works
			_, err := connection.Channel.QueueInspect(queueName)
			Expect(err).To(Equal(amqp.ErrClosed))

			close(done)
		})

		It("should exit on non-recoverable errors", func(done Done) {
			const expectedError = "Exception \\(501\\) Reason: \"EOF\"|connection reset by peer"

			proxy.KillConnected()

			_, err := connection.Channel.QueueInspect(queueName)
			Expect(err.Error()).To(MatchRegexp(expectedError))

			// We'd normally log.Fatalln() here to exit.
			amqpErr := <-fatalErrs
			Expect(amqpErr.Error()).To(MatchRegexp(expectedError))
			Expect(amqpErr.Recover).To(Equal(false))

			// Connection no longer works.
			_, err = connection.Channel.QueueInspect(queueName)
			Expect(err).To(Equal(amqp.ErrClosed))

			close(done)
		})
	})

	Describe("Connecting to a running AMQP service", func() {
		var (
			connection    *QueueConnection
			connectionErr error
		)

		BeforeEach(func() {
			connection, connectionErr = NewQueueConnection(amqpAddr)
			connection.HandleChannelClose = func(_ string) {}
		})

		AfterEach(func() {
			defer connection.Close()
		})

		It("successfully connects to an AMQP service", func() {
			Expect(connectionErr).To(BeNil())
			Expect(connection).ToNot(BeNil())
		})

		It("can close the connection without errors", func() {
			Expect(connection.Close()).To(BeNil())
		})

		It("can declare an exchange", func() {
			var err error
			exchange := "govuk_crawler_worker-some-exchange"

			err = connection.ExchangeDeclare(exchange, "direct")
			Expect(err).To(BeNil())

			err = connection.Channel.ExchangeDelete(exchange, false, false)
			Expect(err).To(BeNil())
		})

		It("can declare a queue", func() {
			var (
				err   error
				queue amqp.Queue
				name  = "govuk_crawler_worker-some-queue"
			)

			queue, err = connection.QueueDeclare(name)
			Expect(err).To(BeNil())
			Expect(queue.Name).To(Equal(name))

			deleted, err := connection.Channel.QueueDelete(name, false, false, false)
			Expect(err).To(BeNil())
			Expect(deleted).To(Equal(0))
		})

		It("can bind a queue to an exchange", func() {
			var err error

			exchangeName := "govuk_crawler_worker-some-binding-exchange"
			queueName := "govuk_crawler_worker-some-binding-queue"

			err = connection.ExchangeDeclare(exchangeName, "direct")
			Expect(err).To(BeNil())

			_, err = connection.QueueDeclare(queueName)
			Expect(err).To(BeNil())

			err = connection.BindQueueToExchange(queueName, exchangeName)
			Expect(err).To(BeNil())

			deleted, err := connection.Channel.QueueDelete(queueName, false, false, false)
			Expect(err).To(BeNil())
			Expect(deleted).To(Equal(0))

			err = connection.Channel.ExchangeDelete(exchangeName, false, false)
			Expect(err).To(BeNil())
		})
	})

	Describe("working with messages on the queue", func() {
		var (
			publisher *QueueConnection
			consumer  *QueueConnection
			err       error
		)

		exchangeName := "govuk_crawler_worker-test-crawler-exchange"
		queueName := "govuk_crawler_worker-test-crawler-queue"

		BeforeEach(func() {
			publisher, err = NewQueueConnection(amqpAddr)
			Expect(err).To(BeNil())
			Expect(publisher).ToNot(BeNil())

			consumer, err = NewQueueConnection(amqpAddr)
			Expect(err).To(BeNil())
			Expect(consumer).ToNot(BeNil())

			publisher.HandleChannelClose = func(_ string) {}
			consumer.HandleChannelClose = func(_ string) {}
		})

		AfterEach(func() {
			// Consumer must Cancel() or Close() before deleting.
			consumer.Close()
			defer publisher.Close()

			deleted, err := publisher.Channel.QueueDelete(queueName, false, false, false)
			Expect(err).To(BeNil())
			Expect(deleted).To(Equal(0))

			err = publisher.Channel.ExchangeDelete(exchangeName, false, false)
			Expect(err).To(BeNil())
		})

		It("should consume and publish messages onto the provided queue and exchange", func(done Done) {
			err = consumer.ExchangeDeclare(exchangeName, "direct")
			Expect(err).To(BeNil())

			_, err = consumer.QueueDeclare(queueName)
			Expect(err).To(BeNil())

			err = consumer.BindQueueToExchange(queueName, exchangeName)
			Expect(err).To(BeNil())

			deliveries, err := consumer.Consume(queueName)
			Expect(err).To(BeNil())

			err = publisher.Publish(exchangeName, "#", "text/plain", "foo")
			Expect(err).To(BeNil())

			item := <-deliveries
			Expect(string(item.Body)).To(Equal("foo"))
			item.Ack(false)
			close(done)
		})
	})
})

// addrFromURL extracts the addr (host:port) from a URL string.
func addrFromURL(URL string) (string, error) {
	parsedURL, err := url.Parse(URL)
	if err != nil {
		return "", err
	}

	return parsedURL.Host, nil
}

// urlChangeAddr changes the addr (host:port) of a URL string.
func urlChangeAddr(origURL, newHost string) (string, error) {
	parsedURL, err := url.Parse(origURL)
	if err != nil {
		return "", err
	}

	parsedURL.Host = newHost
	return parsedURL.String(), nil
}
<|endoftext|>


<commit_before>package raftgorums_test

import (
	"fmt"
	"io/ioutil"
	"net"
	"sync"
	"testing"
	"time"

	"golang.org/x/net/context"

	"google.golang.org/grpc"
	"google.golang.org/grpc/grpclog"

	"github.com/Sirupsen/logrus"
	"github.com/relab/raft"
	"github.com/relab/raft/commonpb"
	"github.com/relab/raft/raftgorums"
)

func TestLeaderElection(t *testing.T) {
	logger := &logrus.Logger{
		Out: ioutil.Discard,
	}
	grpclog.SetLogger(logger)

	var n uint64 = 7

	for i := n; i > 1; i-- {
		for j := i; j > 1; j-- {
			t.Run(fmt.Sprintf("leader %d, n: %d", j, i), func(t *testing.T) {
				testElectLeader(t, i, j)
			})
			t.Run(fmt.Sprintf("leader stepdown %d, n: %d", j, i), func(t *testing.T) {
				testElectLeaderStepDown(t, i, j)
			})
			if i != j {
				t.Run(fmt.Sprintf("leader %d, n: %d, add %d", j, i, i), func(t *testing.T) {
					testProposeConf(t, i, j)
				})
			}
		}
	}
}

type cfg struct {
	id              uint64
	n               uint64
	electionTimeout time.Duration
}

type testServer struct {
	t  *testing.T
	wg *sync.WaitGroup

	timeout    time.Duration
	kv         map[uint64]uint64
	log        map[uint64]*commonpb.Entry
	mem        *raft.Memory
	raft       *raftgorums.Raft
	grpcServer *grpc.Server
}

var port uint64 = 9201

func newTestServer(t *testing.T, wg *sync.WaitGroup, c *cfg, port uint64, exclude ...uint64) *testServer {
	initialCluster := make([]uint64, c.n)
	if len(exclude) > 0 {
		initialCluster = make([]uint64, c.n-1)
	}

	for i := uint64(0); i < uint64(len(initialCluster)); i++ {
		initialCluster[i] = i + 1
	}

	servers := make([]string, c.n)

	for i := c.n; i > 0; i-- {
		servers[i-1] = fmt.Sprintf(":%d", port)
		port++
	}

	kv := make(map[uint64]uint64)
	raftLog := make(map[uint64]*commonpb.Entry)

	server := &testServer{
		t:       t,
		wg:      wg,
		timeout: c.electionTimeout,
		kv:      kv,
		log:     raftLog,
		mem:     raft.NewMemory(kv, raftLog),
	}

	cfg := &raftgorums.Config{
		ID:               c.id,
		Servers:          servers,
		InitialCluster:   initialCluster,
		Storage:          server.mem,
		HeartbeatTimeout: 10 * time.Millisecond,
		ElectionTimeout:  c.electionTimeout,
		Logger: &logrus.Logger{
			Out: ioutil.Discard,
		},
	}

	grpcServer := grpc.NewServer()
	lis, err := net.Listen("tcp", cfg.Servers[c.id-1])

	if err != nil {
		t.Errorf("could not listen on %s: %v", cfg.Servers[c.id-1], err)
	}

	go func() {
		grpcServer.Serve(lis)
		wg.Done()
	}()

	raft := raftgorums.NewRaft(&noopMachine{}, cfg)

	server.grpcServer = grpcServer
	server.raft = raft

	return server
}

func (t *testServer) Stop() {
	t.raft.Stop()
	t.grpcServer.Stop()
}

func (t *testServer) Run() {
	err := t.raft.Run(t.grpcServer)

	if err != nil {
		t.t.Error(err)
	}
}

func testElectLeader(t *testing.T, n uint64, leader uint64) {
	var wg sync.WaitGroup

	servers := make(map[uint64]*testServer, n)

	p := port
	port += n + 1

	for i := n; i > 0; i-- {
		wg.Add(1)
		timeout := time.Second
		if i == leader {
			timeout = 25 * time.Millisecond
		}
		servers[i] = newTestServer(t, &wg, &cfg{
			id:              i,
			n:               n,
			electionTimeout: timeout,
		}, p)
	}

	time.AfterFunc(500*time.Millisecond, func() {
		for i := n; i > 0; i-- {
			servers[i].Stop()
		}
	})

	for i := n; i > 0; i-- {
		go servers[i].Run()
	}
	wg.Wait()

	var votes uint64

	for i := n; i > 0; i-- {
		votes += checkKVs(t, servers[i].kv, 1, 2, leader)
	}

	checkLeaderState(t, servers[leader].raft.State(), raftgorums.Leader)
	checkFollowersState(t, servers, leader)
	checkVotes(t, votes, n)
}

func testElectLeaderStepDown(t *testing.T, n uint64, leader uint64) {
	var wg sync.WaitGroup

	servers := make(map[uint64]*testServer, n)

	p := port
	port += n + 1

	for i := n; i > 0; i-- {
		wg.Add(1)
		timeout := time.Second
		if i == leader {
			timeout = 25 * time.Millisecond
		}
		servers[i] = newTestServer(t, &wg, &cfg{
			id:              i,
			n:               n,
			electionTimeout: timeout,
		}, p)
	}

	time.AfterFunc(500*time.Millisecond, func() {
		for i := n; i > 0; i-- {
			if i != leader {
				servers[i].Stop()
			}
		}

		time.Sleep(4 * servers[leader].timeout)
		servers[leader].Stop()
	})

	for i := n; i > 0; i-- {
		go servers[i].Run()
	}
	wg.Wait()

	var votes uint64

	for i := n; i > 0; i-- {
		votes += checkKVs(t, servers[i].kv, 1, 2, leader)
	}

	checkLeaderState(t, servers[leader].raft.State(), raftgorums.Candidate)
	checkFollowersState(t, servers, leader)
	checkVotes(t, votes, n)
}

func testProposeConf(t *testing.T, n uint64, leader uint64) {
	var wg sync.WaitGroup

	servers := make(map[uint64]*testServer, n)

	p := port
	port += n + 1

	for i := n; i > 0; i-- {
		wg.Add(1)
		timeout := time.Second
		if i == leader {
			timeout = 25 * time.Millisecond
		}
		servers[i] = newTestServer(t, &wg, &cfg{
			id:              i,
			n:               n,
			electionTimeout: timeout,
		}, p, n)
	}

	time.AfterFunc(500*time.Millisecond, func() {
		for i := n; i > 0; i-- {
			servers[i].Stop()
		}
	})

	for i := n; i > 0; i-- {
		go servers[i].Run()
	}

	time.Sleep(250 * time.Millisecond)
	future, err := servers[leader].raft.ProposeConf(context.Background(), &commonpb.ReconfRequest{
		ServerID:   n,
		ReconfType: commonpb.ReconfAdd,
	})

	if err != nil {
		t.Error(err)
		return
	}

	res := <-future.ResultCh()
	reconfStatus := res.Value.(*commonpb.ReconfResponse).Status

	if reconfStatus != commonpb.ReconfOK {
		t.Errorf("reconf: got %d, want %d", reconfStatus, commonpb.ReconfOK)
		return
	}

	wg.Wait()

	var votes uint64

	for i := n; i > 0; i-- {
		votes += checkKVs(t, servers[i].kv, 1, 3, leader)
	}

	checkLeaderState(t, servers[leader].raft.State(), raftgorums.Leader)
	checkFollowersState(t, servers, leader)
	checkVotes(t, votes, n-1)
}

func checkFollowersState(t *testing.T, servers map[uint64]*testServer, leader uint64) {
	for id, server := range servers {
		if id == leader {
			continue
		}
		if server.raft.State() != raftgorums.Follower {
			t.Errorf("unexpected follower state: got %v, want %v", server.raft.State(), raftgorums.Follower)
		}
	}
}

func checkLeaderState(t *testing.T, got, want raftgorums.State) {
	if want == raftgorums.Candidate {
		if got > want {
			t.Errorf("unexpected leader state: got %v, want at most %v", got, want)
		}
		return
	}
	if got != want {
		t.Errorf("unexpected leader state: got %v, want %v", got, want)
	}
}

func checkVotes(t *testing.T, votes, n uint64) {
	if votes < n/2+1 {
		t.Errorf("got %d votes, want at least %d", votes, n/2+1)
	}
}

func checkKVs(t *testing.T, kvs map[uint64]uint64, term, nextIndex, leader uint64) uint64 {
	if kvs[raft.KeyTerm] != term {
		t.Errorf("term: got %d, want %d", kvs[raft.KeyTerm], term)
	}
	if kvs[raft.KeyNextIndex] != nextIndex {
		t.Errorf("next index: got %d, want %d", kvs[raft.KeyNextIndex], nextIndex)
	}
	votedFor := kvs[raft.KeyVotedFor]
	if votedFor != leader && votedFor != raftgorums.None {
		t.Errorf("voted for: got %d, want %d", kvs[raft.KeyVotedFor], leader)
	}

	if votedFor == leader {
		return 1
	}
	return 0
}
<commit_msg>raftgorums/integration_test.go: Add remove server and propose cmd<commit_after>package raftgorums_test

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net"
	"sync"
	"testing"
	"time"

	"golang.org/x/net/context"

	"google.golang.org/grpc"
	"google.golang.org/grpc/grpclog"

	"github.com/Sirupsen/logrus"
	"github.com/relab/raft"
	"github.com/relab/raft/commonpb"
	"github.com/relab/raft/raftgorums"
)

// These tests depend heavily on the speed of your computer. You might need to
// increase some of these timeouts to make the tests pass.
var (
	heartbeat  = 20 * time.Millisecond
	election   = 25 * time.Millisecond
	longEnough = 150 * time.Millisecond
	wait       = 100 * time.Millisecond
)

func TestLeaderElection(t *testing.T) {
	logger := &logrus.Logger{
		Out: ioutil.Discard,
	}
	grpclog.SetLogger(logger)

	var n uint64 = 7

	for i := n; i > 1; i-- {
		for j := i; j > 1; j-- {
			t.Run(fmt.Sprintf("leader %d, n: %d", j, i), func(t *testing.T) {
				testElectLeader(t, i, j)
			})
			t.Run(fmt.Sprintf("leader stepdown %d, n: %d", j, i), func(t *testing.T) {
				testElectLeaderStepDown(t, i, j)
			})
			if i != j {
				t.Run(fmt.Sprintf("leader %d, n: %d, add %d", j, i, i), func(t *testing.T) {
					testProposeConfAdd(t, i, j)
				})
			}
			t.Run(fmt.Sprintf("leader %d, n: %d, remove %d", j, i, i), func(t *testing.T) {
				testProposeConfRemove(t, i, j)
			})
			t.Run(fmt.Sprintf("leader propose cmd %d, n: %d", j, i), func(t *testing.T) {
				testProposeCmdRead(t, i, j)
			})
		}
	}
}

type cfg struct {
	id              uint64
	n               uint64
	electionTimeout time.Duration
}

type testServer struct {
	t  *testing.T
	wg *sync.WaitGroup

	timeout    time.Duration
	kv         map[uint64]uint64
	log        map[uint64]*commonpb.Entry
	mem        *raft.Memory
	raft       *raftgorums.Raft
	grpcServer *grpc.Server
}

var port uint64 = 9201

func newTestServer(t *testing.T, wg *sync.WaitGroup, c *cfg, port uint64, exclude ...uint64) *testServer {
	initialCluster := make([]uint64, c.n)
	if len(exclude) > 0 {
		initialCluster = make([]uint64, c.n-1)
	}

	for i := uint64(0); i < uint64(len(initialCluster)); i++ {
		initialCluster[i] = i + 1
	}

	servers := make([]string, c.n)

	for i := c.n; i > 0; i-- {
		servers[i-1] = fmt.Sprintf(":%d", port)
		port++
	}

	kv := make(map[uint64]uint64)
	raftLog := make(map[uint64]*commonpb.Entry)

	server := &testServer{
		t:       t,
		wg:      wg,
		timeout: c.electionTimeout,
		kv:      kv,
		log:     raftLog,
		mem:     raft.NewMemory(kv, raftLog),
	}

	cfg := &raftgorums.Config{
		ID:               c.id,
		Servers:          servers,
		InitialCluster:   initialCluster,
		Storage:          server.mem,
		HeartbeatTimeout: heartbeat,
		ElectionTimeout:  c.electionTimeout,
		Logger: &logrus.Logger{
			Out: ioutil.Discard,
		},
	}

	grpcServer := grpc.NewServer()
	lis, err := net.Listen("tcp", cfg.Servers[c.id-1])

	if err != nil {
		t.Errorf("could not listen on %s: %v", cfg.Servers[c.id-1], err)
		t.FailNow()
	}

	go func() {
		grpcServer.Serve(lis)
		wg.Done()
	}()

	raft := raftgorums.NewRaft(&noopMachine{}, cfg)

	server.grpcServer = grpcServer
	server.raft = raft

	return server
}

func (t *testServer) Stop() {
	t.raft.Stop()
	t.grpcServer.Stop()
}

func (t *testServer) Run() {
	err := t.raft.Run(t.grpcServer)

	if err != nil {
		t.t.Error(err)
		t.t.FailNow()
	}
}

func testElectLeader(t *testing.T, n uint64, leader uint64) {
	var wg sync.WaitGroup

	servers := make(map[uint64]*testServer, n)

	p := port
	port += n + 10

	for i := n; i > 0; i-- {
		wg.Add(1)
		timeout := longEnough
		if i == leader {
			timeout = election
		}
		servers[i] = newTestServer(t, &wg, &cfg{
			id:              i,
			n:               n,
			electionTimeout: timeout,
		}, p)
	}

	time.AfterFunc(longEnough, func() {
		for i := n; i > 0; i-- {
			servers[i].Stop()
		}
	})

	for i := n; i > 0; i-- {
		go servers[i].Run()
	}
	wg.Wait()

	if servers[leader].kv[raft.KeyTerm] == 0 {
		t.Skipf("skipping test as no leader was elected")
	}

	var votes uint64

	for i := n; i > 0; i-- {
		votes += checkKVs(t, servers[i].kv, 1, 2, leader)
	}

	checkLeaderState(t, servers[leader].raft.State(), raftgorums.Leader)
	checkFollowersState(t, servers, leader)
	checkVotes(t, votes, n)
}

func testElectLeaderStepDown(t *testing.T, n uint64, leader uint64) {
	var wg sync.WaitGroup

	servers := make(map[uint64]*testServer, n)

	p := port
	port += n + 10

	for i := n; i > 0; i-- {
		wg.Add(1)
		timeout := longEnough
		if i == leader {
			timeout = election
		}
		servers[i] = newTestServer(t, &wg, &cfg{
			id:              i,
			n:               n,
			electionTimeout: timeout,
		}, p)
	}

	time.AfterFunc(longEnough, func() {
		for i := n; i > 0; i-- {
			if i != leader {
				servers[i].Stop()
			}
		}

		time.Sleep(3 * servers[leader].timeout)
		servers[leader].Stop()
	})

	for i := n; i > 0; i-- {
		go servers[i].Run()
	}
	wg.Wait()

	if servers[leader].kv[raft.KeyTerm] == 0 {
		t.Skipf("skipping test as no leader was elected")
	}

	var votes uint64

	for i := n; i > 0; i-- {
		votes += checkKVs(t, servers[i].kv, 1, 2, leader)
	}

	checkLeaderState(t, servers[leader].raft.State(), raftgorums.Candidate)
	checkFollowersState(t, servers, leader)
	checkVotes(t, votes, n)
}

func testProposeConfAdd(t *testing.T, n uint64, leader uint64) {
	var wg sync.WaitGroup

	servers := make(map[uint64]*testServer, n)

	p := port
	port += n + 10

	for i := n; i > 0; i-- {
		wg.Add(1)
		timeout := longEnough
		if i == leader {
			timeout = election
		}
		servers[i] = newTestServer(t, &wg, &cfg{
			id:              i,
			n:               n,
			electionTimeout: timeout,
		}, p, n)
	}

	time.AfterFunc(longEnough, func() {
		for i := n; i > 0; i-- {
			servers[i].Stop()
		}
	})

	for i := n; i > 0; i-- {
		go servers[i].Run()
	}

	time.Sleep(wait)

	if servers[leader].kv[raft.KeyTerm] == 0 {
		t.Skipf("skipping test as no leader was elected")
	}

	future, err := servers[leader].raft.ProposeConf(context.Background(), &commonpb.ReconfRequest{
		ServerID:   n,
		ReconfType: commonpb.ReconfAdd,
	})

	if err != nil {
		t.Error(err)
		return
	}

	for i := n; i > 0; i-- {
		if i == leader {
			continue
		}

		_, err := servers[i].raft.ProposeConf(context.Background(), &commonpb.ReconfRequest{})

		if err == nil {
			t.Errorf("can't propose conf on non-leader %d", i)
			return
		}
	}

	res := <-future.ResultCh()
	reconfStatus := res.Value.(*commonpb.ReconfResponse).Status

	if reconfStatus != commonpb.ReconfOK {
		t.Errorf("reconf: got %d, want %d", reconfStatus, commonpb.ReconfOK)
		return
	}

	wg.Wait()

	var votes uint64

	for i := n; i > 0; i-- {
		votes += checkKVs(t, servers[i].kv, 1, 3, leader)
	}

	checkLeaderState(t, servers[leader].raft.State(), raftgorums.Leader)
	checkFollowersState(t, servers, leader)
	checkVotes(t, votes, n-1)
}

func testProposeConfRemove(t *testing.T, n uint64, leader uint64) {
	var wg sync.WaitGroup

	servers := make(map[uint64]*testServer, n)

	p := port
	port += n + 10

	for i := n; i > 0; i-- {
		wg.Add(1)
		timeout := longEnough
		if i == leader {
			timeout = election
		}
		servers[i] = newTestServer(t, &wg, &cfg{
			id:              i,
			n:               n,
			electionTimeout: timeout,
		}, p)
	}

	time.AfterFunc(longEnough, func() {
		for i := n; i > 0; i-- {
			servers[i].Stop()
		}
	})

	for i := n; i > 0; i-- {
		go servers[i].Run()
	}

	time.Sleep(wait)

	if servers[leader].kv[raft.KeyTerm] == 0 {
		t.Skipf("skipping test as no leader was elected")
	}

	future, err := servers[leader].raft.ProposeConf(context.Background(), &commonpb.ReconfRequest{
		ServerID:   n,
		ReconfType: commonpb.ReconfRemove,
	})

	if err != nil {
		t.Error(err)
		return
	}

	res := <-future.ResultCh()
	reconfStatus := res.Value.(*commonpb.ReconfResponse).Status

	if n > 2 {
		if reconfStatus != commonpb.ReconfOK {
			t.Errorf("reconf: got %d, want %d", reconfStatus, commonpb.ReconfOK)
			return
		}
	} else {
		// Cannot do reconf. if next config size < 2.
		if reconfStatus != commonpb.ReconfTimeout {
			t.Errorf("reconf: got %d, want %d", reconfStatus, commonpb.ReconfTimeout)
			return
		}
	}

	wg.Wait()

	var votes uint64

	if leader == n && n != 2 {
		checkLeaderState(t, servers[leader].raft.State(), raftgorums.Inactive)
		votes = checkKVs(t, servers[n].kv, 1, 3, leader)
	} else {
		checkLeaderState(t, servers[leader].raft.State(), raftgorums.Leader)
		votes = checkKVs(t, servers[n].kv, 1, 2, leader)
	}

	if n == 2 {
		votes += checkKVs(t, servers[1].kv, 1, 2, leader)
	} else {
		for i := n - 1; i > 0; i-- {
			votes += checkKVs(t, servers[i].kv, 1, 3, leader)
		}
	}

	checkFollowersState(t, servers, leader)
	checkVotes(t, votes, n)
}

func testProposeCmdRead(t *testing.T, n uint64, leader uint64) {
	var wg sync.WaitGroup

	servers := make(map[uint64]*testServer, n)

	p := port
	port += n + 10

	for i := n; i > 0; i-- {
		wg.Add(1)
		timeout := longEnough
		if i == leader {
			timeout = election
		}
		servers[i] = newTestServer(t, &wg, &cfg{
			id:              i,
			n:               n,
			electionTimeout: timeout,
		}, p)
	}

	time.AfterFunc(longEnough, func() {
		for i := n; i > 0; i-- {
			servers[i].Stop()
		}
	})

	for i := n; i > 0; i-- {
		go servers[i].Run()
	}

	time.Sleep(wait)

	if servers[leader].kv[raft.KeyTerm] == 0 {
		t.Skipf("skipping test as no leader was elected")
	}

	future, err := servers[leader].raft.ProposeCmd(context.Background(), raft.NOOP)

	if err != nil {
		t.Error(err)
		return
	}

	for i := n; i > 0; i-- {
		if i == leader {
			continue
		}

		_, err := servers[i].raft.ProposeCmd(context.Background(), raft.NOOP)

		if err == nil {
			t.Errorf("can't propose cmd on non-leader %d", i)
			return
		}
	}

	res := <-future.ResultCh()

	entry := res.Value.(*commonpb.Entry)

	if res.Index != 2 {
		t.Errorf("index: got %d, want %d", res.Index, 2)
	}

	if !bytes.Equal(entry.Data, raft.NOOP) {
		t.Errorf("data: got %s, want %s", entry.Data, raft.NOOP)
	}

	future, err = servers[leader].raft.ReadCmd(context.Background(), raft.NOOP)

	if err != nil {
		t.Error(err)
		return
	}

	for i := n; i > 0; i-- {
		if i == leader {
			continue
		}

		_, err := servers[i].raft.ReadCmd(context.Background(), raft.NOOP)

		if err == nil {
			t.Errorf("can't read cmd on non-leader %d", i)
			return
		}
	}

	res = <-future.ResultCh()

	entry = res.Value.(*commonpb.Entry)

	if res.Index != 0 {
		t.Errorf("index: got %d, want %d", res.Index, 0)
	}

	if !bytes.Equal(entry.Data, raft.NOOP) {
		t.Errorf("data: got %s, want %s", entry.Data, raft.NOOP)
	}

	wg.Wait()

	var votes uint64

	for i := n; i > 0; i-- {
		votes += checkKVs(t, servers[i].kv, 1, 3, leader)
	}

	checkLeaderState(t, servers[leader].raft.State(), raftgorums.Leader)
	checkFollowersState(t, servers, leader)
	checkVotes(t, votes, n)
}

func checkFollowersState(t *testing.T, servers map[uint64]*testServer, leader uint64) {
	for id, server := range servers {
		if id == leader {
			continue
		}
		if server.raft.State() != raftgorums.Follower {
			t.Errorf("unexpected follower state: got %v, want %v", server.raft.State(), raftgorums.Follower)
		}
	}
}

func checkLeaderState(t *testing.T, got, want raftgorums.State) {
	if want == raftgorums.Candidate {
		if got > want {
			t.Errorf("unexpected leader state: got %v, want at most %v", got, want)
		}
		return
	}
	if got != want {
		t.Errorf("unexpected leader state: got %v, want %v", got, want)
	}
}

func checkVotes(t *testing.T, votes, n uint64) {
	if votes < n/2+1 {
		t.Errorf("got %d votes, want at least %d", votes, n/2+1)
	}
}

func checkKVs(t *testing.T, kvs map[uint64]uint64, term, nextIndex, leader uint64) uint64 {
	if kvs[raft.KeyTerm] != term {
		t.Errorf("term: got %d, want %d", kvs[raft.KeyTerm], term)
	}
	if kvs[raft.KeyNextIndex] != nextIndex {
		t.Errorf("next index: got %d, want %d", kvs[raft.KeyNextIndex], nextIndex)
	}
	votedFor := kvs[raft.KeyVotedFor]
	if votedFor != leader && votedFor != raftgorums.None {
		t.Errorf("voted for: got %d, want %d", kvs[raft.KeyVotedFor], leader)
	}

	if votedFor == leader {
		return 1
	}
	return 0
}
<|endoftext|>


<commit_before>package of10

import "net"

type FeaturesRequest struct {
	Header
}

type FeaturesReply struct {
	Header
	DatapathId   DatapathId
	Buffers      uint32
	Tables       uint8
	pad          [3]uint8
	Capabilities Capability
	Actions      ActionType
	Ports        []PhysicalPort
}

type DatapathId uint64
type Capability uint32

const (
	OFPC_FLOW_STATS Capability = 1 << iota
	OFPC_TABLE_STATS
	OFPC_PORT_STATS
	OFPC_STP
	OFPC_RESERVED
	OFPC_IP_REASM
	OFPC_QUEUE_STATS
	OFPC_ARP_MATCH_IP
)

var Capabilities = struct {
	FlowStats    Capability
	TableStats   Capability
	PortStats    Capability
	Stp          Capability
	Reserved     Capability
	IpReassemble Capability
	QueueStats   Capability
	ArpMatchIp   Capability
}{
	OFPC_FLOW_STATS,
	OFPC_TABLE_STATS,
	OFPC_PORT_STATS,
	OFPC_STP,
	OFPC_RESERVED,
	OFPC_IP_REASM,
	OFPC_QUEUE_STATS,
	OFPC_ARP_MATCH_IP,
}

type GetConfigRequest struct {
	Header
}

type SwitchConfig struct {
	Header
	Flags          ConfigFlag
	MissSendLength uint16
}

type GetConfigReply struct {
	Header
	Flags          ConfigFlag
	MissSendLength uint16
}

type SetConfig struct {
	Header
	Flags          ConfigFlag
	MissSendLength uint16
}

type ConfigFlag uint16

const (
	OFPC_FRAG_NORMAL ConfigFlag = iota
	OFPC_FRAG_DROP
	OFPC_FRAG_REASM
	OFPC_FRAG_MASK
)

var ConfigFlags = struct {
	FragmentNormal     ConfigFlag
	FragmentDrop       ConfigFlag
	FragmentReassemble ConfigFlag
	FragmentMask       ConfigFlag
}{
	OFPC_FRAG_NORMAL,
	OFPC_FRAG_DROP,
	OFPC_FRAG_REASM,
	OFPC_FRAG_MASK,
}

type FlowMod struct {
	Header
	Match       Match
	Cookie      Cookie
	Command     FlowModCommand
	IdleTimeout uint16
	HardTimeout uint16
	Priority    uint16
	BufferId    BufferId
	OutPort     PortNumber
	Flags       FlowModFlag
	Actions     []Action
}

type Cookie uint64
type FlowModCommand uint16
type BufferId uint32
type FlowModFlag uint16

const (
	OFPFC_ADD FlowModCommand = iota
	OFPFC_MODIFY
	OFPFC_MODIFY_STRICT
	OFPFC_DELETE
	OFPFC_DELETE_STRICT
)

var FlowModCommands = struct {
	Add          FlowModCommand
	Modify       FlowModCommand
	ModifyStrict FlowModCommand
	Delete       FlowModCommand
	DeleteStrict FlowModCommand
}{
	OFPFC_ADD,
	OFPFC_MODIFY,
	OFPFC_MODIFY_STRICT,
	OFPFC_DELETE,
	OFPFC_DELETE_STRICT,
}

const (
	OFPFF_SEND_FLOW_REM FlowModFlag = 1 << iota
	OFPFF_CHECK_OVERLAP
	OFPFF_EMERG
)

var FlowModFlags = struct {
	SendFlowRemoved FlowModFlag
	CheckOverlap    FlowModFlag
	Emergency       FlowModFlag
}{
	OFPFF_SEND_FLOW_REM,
	OFPFF_CHECK_OVERLAP,
	OFPFF_EMERG,
}

type PortMod struct {
	Header
	PortNumber      PortNumber
	HardwareAddress net.HardwareAddr
	Config          PortConfig
	Mask            PortConfig
	Advertise       PortFeature
	pad             [4]uint8
}

type QueueGetConfigRequest struct {
	Header
	Port PortNumber
	pad  [2]uint8
}

type QueueGetConfigReply struct {
	Header
	Port   PortNumber
	pad    [6]uint8
	Queues []PacketQueue
}

type StatsRequest struct {
	Header
	Type  StatsType
	Flags uint16
	Body  []uint8
}

type StatsReply struct {
	Header
	Type  StatsType
	Flags uint16
	Body  []uint8
}

type StatsType uint16

const (
	OFPST_DESC StatsType = iota
	OFPST_FLOW
	OFPST_AGGREGATE
	OFPST_TABLE
	OFPST_PORT
	OFPST_QUEUE
	OFPST_VENDOR StatsType = 0xffff
)

var StatsTypes = struct {
	Description StatsType
	Flow        StatsType
	Aggregate   StatsType
	Table       StatsType
	Port        StatsType
	Queue       StatsType
	Vendor      StatsType
}{
	OFPST_DESC,
	OFPST_FLOW,
	OFPST_AGGREGATE,
	OFPST_TABLE,
	OFPST_PORT,
	OFPST_QUEUE,
	OFPST_VENDOR,
}

type DescriptionStats struct {
	Manufacturer []uint8
	Hardware     []uint8
	Software     []uint8
	SerialNumber []uint8
	Datapath     []uint8
}

type FlowStatsRequest struct {
	Match   Match
	TalbeId uint8
	pad     uint8
	OutPort PortNumber
}

type FlowStatsReply struct {
	Length          uint16
	TableId         uint8
	pad             [1]uint8
	Match           Match
	DurationSec     uint32
	DurationNanoSec uint32
	Priority        uint16
	IdleTimeout     uint16
	HardTimeout     uint16
	pad2            [6]uint8
	Cookie          Cookie
	PacketCount     uint64
	ByteCount       uint64
	Actions         []ActionHeader
}

type AggregateStatsRequest struct {
	Match   Match
	TableId uint8
	pad     [1]uint8
	OutPort PortNumber
}

type AggregateStatsReply struct {
	PacketCount uint64
	ByteCount   uint64
	FlowCount   uint64
	pad         [4]uint8
}

type TableStatsReply struct {
	TableId      uint8
	pad          [3]uint8
	Name         []uint8
	Wildcards    Wildcard
	MaxEntries   uint32
	ActiveCount  uint32
	LookupCount  uint32
	MatchedCount uint32
}

type PortStatsRequest struct {
	PortNumber PortNumber
	pad        [6]uint8
}

type PortStatsReply struct {
	PortNumber      PortNumber
	pad             [6]uint8
	RxPackets       uint64
	TxPackets       uint64
	RxBytes         uint64
	TxBytes         uint64
	RxDropped       uint64
	TxDropped       uint64
	RxErrors        uint64
	TxErrors        uint64
	RxFrameErrors   uint64
	RxOverrunErrors uint64
	RxCrcErrors     uint64
	Collisions      uint64
}

type QueueStatsRequest struct {
	PortNumber PortNumber
	pad        [2]uint8
	QueueId    uint32
}

type QueueStatsReply struct {
	PortNumber PortNumber
	pad        [2]uint8
	QueueId    uint32
	TxBytes    uint64
	TxPackets  uint64
	TxErrors   uint64
}

type PacketOut struct {
	Header
	BufferId      uint32
	InPort        PortNumber
	ActionsLength uint16
	Actions       []ActionHeader
	Data          []uint8
}

type BarrierRequest struct {
	Header
}

type BarrierReply struct {
	Header
}

type PacketIn struct {
	Header
	BufferId    uint32
	TotalLength uint16
	InPort      PortNumber
	Reason      PacketInReason
	pad         [1]uint8
	Data        []uint8
}

type PacketInReason uint8

const (
	OFPR_NO_MATCH PacketInReason = iota
	OFPR_ACTION
)

var PacketInReasons = struct {
	NoMatch PacketInReason
	Action  PacketInReason
}{
	OFPR_NO_MATCH,
	OFPR_ACTION,
}

type FlowRemoved struct {
	Header
	Match           Match
	Cookie          Cookie
	Priority        uint16
	Reason          FlowRemovedReason
	pad             [1]uint8
	DurationSec     uint32
	DurationNanoSec uint32
	IdleTimeout     uint16
	pad2            [2]uint8
	PacketCount     uint64
	ByteCount       uint64
}

type FlowRemovedReason uint8

const (
	OFPRR_IDLE_TIMEOUT FlowRemovedReason = iota
	OFPRR_HARD_TIMEOUT
	OFPRR_DELETE
)

var FlowRemovedReasons = struct {
	IdleTimeout FlowRemovedReason
	HardTimeout FlowRemovedReason
	Delete      FlowRemovedReason
}{
	OFPRR_IDLE_TIMEOUT,
	OFPRR_HARD_TIMEOUT,
	OFPRR_DELETE,
}

type PortStatus struct {
	Header
	Reason      PortStatusReason
	pad         [7]uint8
	Description PhysicalPort
}

type PortStatusReason uint8

const (
	OFPPR_ADD PortStatusReason = iota
	OFPPR_DELETE
	OFPPR_MODIFY
)

var PortStatusReasons = struct {
	Add    PortStatusReason
	Delete PortStatusReason
	Modify PortStatusReason
}{
	OFPPR_ADD,
	OFPPR_DELETE,
	OFPPR_MODIFY,
}

type ErrorMessage struct {
	Header
	Type ErrorType
	Code ErrorCode
	Data []uint8
}

type ErrorType uint16

const (
	OFPET_HELLO_FAILED ErrorType = iota
	OFPET_BAD_REQUEST
	OFPET_BAD_ACTION
	OFPET_FLOW_MOD_FAILED
	OFPET_PORT_MOD_FAILED
	OFPET_QUEUE_OP_FAILED
)

type ErrorCode uint16

// ErrorCode for Hello Failed
const (
	OFPHFC_INCOMPATIBLE ErrorCode = iota
	OFPHFC_EPERM
)

var HelloFailedCodes = struct {
	Incompatible    ErrorCode
	PermissionError ErrorCode
}{
	OFPHFC_INCOMPATIBLE,
	OFPHFC_EPERM,
}

// ErrorCode for Bad Request
const (
	OFPBRC_BAD_VERSION ErrorCode = iota
	OFPBRC_BAD_TYPE
	OFPBRC_BAD_STAT
	OFPBRC_BAD_VENDOR
	OFPBRC_BAD_SUBTYPE
	OFPBRC_EPERM
	OFPBRC_BAD_LEN
	OFPBRC_BUFFER_EMPTY
	OFPBRC_BUFFER_UNKNOWN
)

var BadRequestCodes = struct {
	BadVersion       ErrorCode
	BadType          ErrorCode
	BadStatRequest   ErrorCode
	BadVendorType    ErrorCode
	BadVendorSubType ErrorCode
	PermissionError  ErrorCode
	BadLength        ErrorCode
	BufferEmpty      ErrorCode
	BufferUnknown    ErrorCode
}{
	OFPBRC_BAD_VERSION,
	OFPBRC_BAD_TYPE,
	OFPBRC_BAD_STAT,
	OFPBRC_BAD_VENDOR,
	OFPBRC_BAD_SUBTYPE,
	OFPBRC_EPERM,
	OFPBRC_BAD_LEN,
	OFPBRC_BUFFER_EMPTY,
	OFPBRC_BUFFER_UNKNOWN,
}

// ErrorCode for Bad Action
const (
	OFPBAC_BAD_TYPE ErrorCode = iota
	OFPBAC_BAD_LEN
	OFPBAC_BAD_VENDOR
	OFPBAC_BAD_VENDOR_TYPE
	OFPBAC_BAD_OUT_PORT
	OFPBAC_BAD_ARGUMENT
	OFPBAC_EPERM
	OFPBAC_TOO_MANY
	OFPBAC_BAD_QUEUE
)

var BadActionCodes = struct {
	BadType         ErrorCode
	BadLength       ErrorCode
	BadVendorId     ErrorCode
	BadVendorType   ErrorCode
	BadOutPort      ErrorCode
	BadArgument     ErrorCode
	PermissionError ErrorCode
	TooManyActions  ErrorCode
	BadQeueu        ErrorCode
}{
	OFPBAC_BAD_TYPE,
	OFPBAC_BAD_LEN,
	OFPBAC_BAD_VENDOR,
	OFPBAC_BAD_VENDOR_TYPE,
	OFPBAC_BAD_OUT_PORT,
	OFPBAC_BAD_ARGUMENT,
	OFPBAC_EPERM,
	OFPBAC_TOO_MANY,
	OFPBAC_BAD_QUEUE,
}

// ErrorCode for Flow Mod Failed
const (
	OFPFMFC_ALL_TABLES_FULL ErrorCode = iota
	OFPFMFC_OVERLAP
	OFPFMFC_EPERM
	OFPFMFC_BAD_EMERG_TIMEOUT
	OFPFMFC_BAD_COMMAND
	OFPFMFC_UNSUPPORTED
)

var FlowModFailedCodes = struct {
	AllTablesFull       ErrorCode
	Overlap             ErrorCode
	PermissionError     ErrorCode
	BadEmergencyTimeout ErrorCode
	BadCommand          ErrorCode
	Unsupported         ErrorCode
}{
	OFPFMFC_ALL_TABLES_FULL,
	OFPFMFC_OVERLAP,
	OFPFMFC_EPERM,
	OFPFMFC_BAD_EMERG_TIMEOUT,
	OFPFMFC_BAD_COMMAND,
	OFPFMFC_UNSUPPORTED,
}

// ErrorCode for Port Mod Failed
const (
	OFPPMFC_BAD_PORT ErrorCode = iota
	OFPPMFC_BAD_HW_ADDR
)

var PortModFailedCode = struct {
	BadPort            ErrorCode
	BadHardwareAddress ErrorCode
}{
	OFPPMFC_BAD_PORT,
	OFPPMFC_BAD_HW_ADDR,
}

// ErrorCode for Queue Op Failed
const (
	OFPQOFC_BAD_Port ErrorCode = iota
	OFPQOFC_BAD_QUEUE
	OFPQOFC_EPERM
)

var QueueOperationFailedCodes = struct {
	BadPort         ErrorCode
	BadQueue        ErrorCode
	PermissionError ErrorCode
}{
	OFPQOFC_BAD_Port,
	OFPQOFC_BAD_QUEUE,
	OFPQOFC_EPERM,
}

type Hello struct {
	Header
}

type EchoRequest struct {
	Header
	Body []uint8
}

type EchoReply struct {
	Header
	Body []uint8
}

type VendorMessage struct {
	Header
	Vendor VendorId
	Body   []uint8
}
<commit_msg>Implement deserialization for Hello<commit_after>package of10

import (
	"bytes"
	"encoding/binary"
	"net"
)

type FeaturesRequest struct {
	Header
}

type FeaturesReply struct {
	Header
	DatapathId   DatapathId
	Buffers      uint32
	Tables       uint8
	pad          [3]uint8
	Capabilities Capability
	Actions      ActionType
	Ports        []PhysicalPort
}

type DatapathId uint64
type Capability uint32

const (
	OFPC_FLOW_STATS Capability = 1 << iota
	OFPC_TABLE_STATS
	OFPC_PORT_STATS
	OFPC_STP
	OFPC_RESERVED
	OFPC_IP_REASM
	OFPC_QUEUE_STATS
	OFPC_ARP_MATCH_IP
)

var Capabilities = struct {
	FlowStats    Capability
	TableStats   Capability
	PortStats    Capability
	Stp          Capability
	Reserved     Capability
	IpReassemble Capability
	QueueStats   Capability
	ArpMatchIp   Capability
}{
	OFPC_FLOW_STATS,
	OFPC_TABLE_STATS,
	OFPC_PORT_STATS,
	OFPC_STP,
	OFPC_RESERVED,
	OFPC_IP_REASM,
	OFPC_QUEUE_STATS,
	OFPC_ARP_MATCH_IP,
}

type GetConfigRequest struct {
	Header
}

type SwitchConfig struct {
	Header
	Flags          ConfigFlag
	MissSendLength uint16
}

type GetConfigReply struct {
	Header
	Flags          ConfigFlag
	MissSendLength uint16
}

type SetConfig struct {
	Header
	Flags          ConfigFlag
	MissSendLength uint16
}

type ConfigFlag uint16

const (
	OFPC_FRAG_NORMAL ConfigFlag = iota
	OFPC_FRAG_DROP
	OFPC_FRAG_REASM
	OFPC_FRAG_MASK
)

var ConfigFlags = struct {
	FragmentNormal     ConfigFlag
	FragmentDrop       ConfigFlag
	FragmentReassemble ConfigFlag
	FragmentMask       ConfigFlag
}{
	OFPC_FRAG_NORMAL,
	OFPC_FRAG_DROP,
	OFPC_FRAG_REASM,
	OFPC_FRAG_MASK,
}

type FlowMod struct {
	Header
	Match       Match
	Cookie      Cookie
	Command     FlowModCommand
	IdleTimeout uint16
	HardTimeout uint16
	Priority    uint16
	BufferId    BufferId
	OutPort     PortNumber
	Flags       FlowModFlag
	Actions     []Action
}

type Cookie uint64
type FlowModCommand uint16
type BufferId uint32
type FlowModFlag uint16

const (
	OFPFC_ADD FlowModCommand = iota
	OFPFC_MODIFY
	OFPFC_MODIFY_STRICT
	OFPFC_DELETE
	OFPFC_DELETE_STRICT
)

var FlowModCommands = struct {
	Add          FlowModCommand
	Modify       FlowModCommand
	ModifyStrict FlowModCommand
	Delete       FlowModCommand
	DeleteStrict FlowModCommand
}{
	OFPFC_ADD,
	OFPFC_MODIFY,
	OFPFC_MODIFY_STRICT,
	OFPFC_DELETE,
	OFPFC_DELETE_STRICT,
}

const (
	OFPFF_SEND_FLOW_REM FlowModFlag = 1 << iota
	OFPFF_CHECK_OVERLAP
	OFPFF_EMERG
)

var FlowModFlags = struct {
	SendFlowRemoved FlowModFlag
	CheckOverlap    FlowModFlag
	Emergency       FlowModFlag
}{
	OFPFF_SEND_FLOW_REM,
	OFPFF_CHECK_OVERLAP,
	OFPFF_EMERG,
}

type PortMod struct {
	Header
	PortNumber      PortNumber
	HardwareAddress net.HardwareAddr
	Config          PortConfig
	Mask            PortConfig
	Advertise       PortFeature
	pad             [4]uint8
}

type QueueGetConfigRequest struct {
	Header
	Port PortNumber
	pad  [2]uint8
}

type QueueGetConfigReply struct {
	Header
	Port   PortNumber
	pad    [6]uint8
	Queues []PacketQueue
}

type StatsRequest struct {
	Header
	Type  StatsType
	Flags uint16
	Body  []uint8
}

type StatsReply struct {
	Header
	Type  StatsType
	Flags uint16
	Body  []uint8
}

type StatsType uint16

const (
	OFPST_DESC StatsType = iota
	OFPST_FLOW
	OFPST_AGGREGATE
	OFPST_TABLE
	OFPST_PORT
	OFPST_QUEUE
	OFPST_VENDOR StatsType = 0xffff
)

var StatsTypes = struct {
	Description StatsType
	Flow        StatsType
	Aggregate   StatsType
	Table       StatsType
	Port        StatsType
	Queue       StatsType
	Vendor      StatsType
}{
	OFPST_DESC,
	OFPST_FLOW,
	OFPST_AGGREGATE,
	OFPST_TABLE,
	OFPST_PORT,
	OFPST_QUEUE,
	OFPST_VENDOR,
}

type DescriptionStats struct {
	Manufacturer []uint8
	Hardware     []uint8
	Software     []uint8
	SerialNumber []uint8
	Datapath     []uint8
}

type FlowStatsRequest struct {
	Match   Match
	TalbeId uint8
	pad     uint8
	OutPort PortNumber
}

type FlowStatsReply struct {
	Length          uint16
	TableId         uint8
	pad             [1]uint8
	Match           Match
	DurationSec     uint32
	DurationNanoSec uint32
	Priority        uint16
	IdleTimeout     uint16
	HardTimeout     uint16
	pad2            [6]uint8
	Cookie          Cookie
	PacketCount     uint64
	ByteCount       uint64
	Actions         []ActionHeader
}

type AggregateStatsRequest struct {
	Match   Match
	TableId uint8
	pad     [1]uint8
	OutPort PortNumber
}

type AggregateStatsReply struct {
	PacketCount uint64
	ByteCount   uint64
	FlowCount   uint64
	pad         [4]uint8
}

type TableStatsReply struct {
	TableId      uint8
	pad          [3]uint8
	Name         []uint8
	Wildcards    Wildcard
	MaxEntries   uint32
	ActiveCount  uint32
	LookupCount  uint32
	MatchedCount uint32
}

type PortStatsRequest struct {
	PortNumber PortNumber
	pad        [6]uint8
}

type PortStatsReply struct {
	PortNumber      PortNumber
	pad             [6]uint8
	RxPackets       uint64
	TxPackets       uint64
	RxBytes         uint64
	TxBytes         uint64
	RxDropped       uint64
	TxDropped       uint64
	RxErrors        uint64
	TxErrors        uint64
	RxFrameErrors   uint64
	RxOverrunErrors uint64
	RxCrcErrors     uint64
	Collisions      uint64
}

type QueueStatsRequest struct {
	PortNumber PortNumber
	pad        [2]uint8
	QueueId    uint32
}

type QueueStatsReply struct {
	PortNumber PortNumber
	pad        [2]uint8
	QueueId    uint32
	TxBytes    uint64
	TxPackets  uint64
	TxErrors   uint64
}

type PacketOut struct {
	Header
	BufferId      uint32
	InPort        PortNumber
	ActionsLength uint16
	Actions       []ActionHeader
	Data          []uint8
}

type BarrierRequest struct {
	Header
}

type BarrierReply struct {
	Header
}

type PacketIn struct {
	Header
	BufferId    uint32
	TotalLength uint16
	InPort      PortNumber
	Reason      PacketInReason
	pad         [1]uint8
	Data        []uint8
}

type PacketInReason uint8

const (
	OFPR_NO_MATCH PacketInReason = iota
	OFPR_ACTION
)

var PacketInReasons = struct {
	NoMatch PacketInReason
	Action  PacketInReason
}{
	OFPR_NO_MATCH,
	OFPR_ACTION,
}

type FlowRemoved struct {
	Header
	Match           Match
	Cookie          Cookie
	Priority        uint16
	Reason          FlowRemovedReason
	pad             [1]uint8
	DurationSec     uint32
	DurationNanoSec uint32
	IdleTimeout     uint16
	pad2            [2]uint8
	PacketCount     uint64
	ByteCount       uint64
}

type FlowRemovedReason uint8

const (
	OFPRR_IDLE_TIMEOUT FlowRemovedReason = iota
	OFPRR_HARD_TIMEOUT
	OFPRR_DELETE
)

var FlowRemovedReasons = struct {
	IdleTimeout FlowRemovedReason
	HardTimeout FlowRemovedReason
	Delete      FlowRemovedReason
}{
	OFPRR_IDLE_TIMEOUT,
	OFPRR_HARD_TIMEOUT,
	OFPRR_DELETE,
}

type PortStatus struct {
	Header
	Reason      PortStatusReason
	pad         [7]uint8
	Description PhysicalPort
}

type PortStatusReason uint8

const (
	OFPPR_ADD PortStatusReason = iota
	OFPPR_DELETE
	OFPPR_MODIFY
)

var PortStatusReasons = struct {
	Add    PortStatusReason
	Delete PortStatusReason
	Modify PortStatusReason
}{
	OFPPR_ADD,
	OFPPR_DELETE,
	OFPPR_MODIFY,
}

type ErrorMessage struct {
	Header
	Type ErrorType
	Code ErrorCode
	Data []uint8
}

type ErrorType uint16

const (
	OFPET_HELLO_FAILED ErrorType = iota
	OFPET_BAD_REQUEST
	OFPET_BAD_ACTION
	OFPET_FLOW_MOD_FAILED
	OFPET_PORT_MOD_FAILED
	OFPET_QUEUE_OP_FAILED
)

type ErrorCode uint16

// ErrorCode for Hello Failed
const (
	OFPHFC_INCOMPATIBLE ErrorCode = iota
	OFPHFC_EPERM
)

var HelloFailedCodes = struct {
	Incompatible    ErrorCode
	PermissionError ErrorCode
}{
	OFPHFC_INCOMPATIBLE,
	OFPHFC_EPERM,
}

// ErrorCode for Bad Request
const (
	OFPBRC_BAD_VERSION ErrorCode = iota
	OFPBRC_BAD_TYPE
	OFPBRC_BAD_STAT
	OFPBRC_BAD_VENDOR
	OFPBRC_BAD_SUBTYPE
	OFPBRC_EPERM
	OFPBRC_BAD_LEN
	OFPBRC_BUFFER_EMPTY
	OFPBRC_BUFFER_UNKNOWN
)

var BadRequestCodes = struct {
	BadVersion       ErrorCode
	BadType          ErrorCode
	BadStatRequest   ErrorCode
	BadVendorType    ErrorCode
	BadVendorSubType ErrorCode
	PermissionError  ErrorCode
	BadLength        ErrorCode
	BufferEmpty      ErrorCode
	BufferUnknown    ErrorCode
}{
	OFPBRC_BAD_VERSION,
	OFPBRC_BAD_TYPE,
	OFPBRC_BAD_STAT,
	OFPBRC_BAD_VENDOR,
	OFPBRC_BAD_SUBTYPE,
	OFPBRC_EPERM,
	OFPBRC_BAD_LEN,
	OFPBRC_BUFFER_EMPTY,
	OFPBRC_BUFFER_UNKNOWN,
}

// ErrorCode for Bad Action
const (
	OFPBAC_BAD_TYPE ErrorCode = iota
	OFPBAC_BAD_LEN
	OFPBAC_BAD_VENDOR
	OFPBAC_BAD_VENDOR_TYPE
	OFPBAC_BAD_OUT_PORT
	OFPBAC_BAD_ARGUMENT
	OFPBAC_EPERM
	OFPBAC_TOO_MANY
	OFPBAC_BAD_QUEUE
)

var BadActionCodes = struct {
	BadType         ErrorCode
	BadLength       ErrorCode
	BadVendorId     ErrorCode
	BadVendorType   ErrorCode
	BadOutPort      ErrorCode
	BadArgument     ErrorCode
	PermissionError ErrorCode
	TooManyActions  ErrorCode
	BadQeueu        ErrorCode
}{
	OFPBAC_BAD_TYPE,
	OFPBAC_BAD_LEN,
	OFPBAC_BAD_VENDOR,
	OFPBAC_BAD_VENDOR_TYPE,
	OFPBAC_BAD_OUT_PORT,
	OFPBAC_BAD_ARGUMENT,
	OFPBAC_EPERM,
	OFPBAC_TOO_MANY,
	OFPBAC_BAD_QUEUE,
}

// ErrorCode for Flow Mod Failed
const (
	OFPFMFC_ALL_TABLES_FULL ErrorCode = iota
	OFPFMFC_OVERLAP
	OFPFMFC_EPERM
	OFPFMFC_BAD_EMERG_TIMEOUT
	OFPFMFC_BAD_COMMAND
	OFPFMFC_UNSUPPORTED
)

var FlowModFailedCodes = struct {
	AllTablesFull       ErrorCode
	Overlap             ErrorCode
	PermissionError     ErrorCode
	BadEmergencyTimeout ErrorCode
	BadCommand          ErrorCode
	Unsupported         ErrorCode
}{
	OFPFMFC_ALL_TABLES_FULL,
	OFPFMFC_OVERLAP,
	OFPFMFC_EPERM,
	OFPFMFC_BAD_EMERG_TIMEOUT,
	OFPFMFC_BAD_COMMAND,
	OFPFMFC_UNSUPPORTED,
}

// ErrorCode for Port Mod Failed
const (
	OFPPMFC_BAD_PORT ErrorCode = iota
	OFPPMFC_BAD_HW_ADDR
)

var PortModFailedCode = struct {
	BadPort            ErrorCode
	BadHardwareAddress ErrorCode
}{
	OFPPMFC_BAD_PORT,
	OFPPMFC_BAD_HW_ADDR,
}

// ErrorCode for Queue Op Failed
const (
	OFPQOFC_BAD_Port ErrorCode = iota
	OFPQOFC_BAD_QUEUE
	OFPQOFC_EPERM
)

var QueueOperationFailedCodes = struct {
	BadPort         ErrorCode
	BadQueue        ErrorCode
	PermissionError ErrorCode
}{
	OFPQOFC_BAD_Port,
	OFPQOFC_BAD_QUEUE,
	OFPQOFC_EPERM,
}

type Hello struct {
	Header
}

func (m *Hello) FillBody(body []byte) error {
	return nil
}

type EchoRequest struct {
	Header
	Body []uint8
}

type EchoReply struct {
	Header
	Body []uint8
}

type VendorMessage struct {
	Header
	Vendor VendorId
	Body   []uint8
}
<|endoftext|>