<commit_before>/*
Copyright 2016 Tuenti Technologies S.L. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"strings"
	"time"

	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/pkg/api"
	"k8s.io/client-go/pkg/api/meta"
	"k8s.io/client-go/pkg/api/v1"
	"k8s.io/client-go/pkg/util/wait"
	"k8s.io/client-go/pkg/watch"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
)

var defaultPortMode = "http"
var reconnectTimeoutSeconds = 300

func init() {
	flag.StringVar(&defaultPortMode, "default-port-mode", defaultPortMode, "Default mode for service ports")
	flag.IntVar(&reconnectTimeoutSeconds, "reconnect-timeout", reconnectTimeoutSeconds, "Reconnect timeout in seconds")
}

type KubernetesClient struct {
	config    *rest.Config
	clientset *kubernetes.Clientset

	nodeStore      NodeStore
	serviceStore   ServiceStore
	endpointsStore EndpointsStore

	nodeWatcher      watch.Interface
	serviceWatcher   watch.Interface
	endpointsWatcher watch.Interface

	lastResourceVersion string

	updaterBuilder UpdaterBuilder
	eventForwarder func(watch.Event)

	notifiers []Notifier
	templates []Template

	domain string
}

const (
	ExternalDomainsAnnotation = "kube2lb/external-domains"
	PortModeAnnotation        = "kube2lb/port-mode"
	BackendTimeoutAnnotation  = "kube2lb/backend-timeout"
)

func NewKubernetesClient(kubecfg, apiserver, domain string) (*KubernetesClient, error) {
	config, err := clientcmd.BuildConfigFromFlags(apiserver, kubecfg)
	if err != nil {
		return nil, err
	}

	clientset, err := kubernetes.NewForConfig(config)
	if err != nil {
		return nil, err
	}

	kc := &KubernetesClient{
		config:         config,
		clientset:      clientset,
		notifiers:      make([]Notifier, 0, 10),
		templates:      make([]Template, 0, 10),
		domain:         domain,
		updaterBuilder: NewUpdater,
	}

	if err := kc.connect(); err != nil {
		return nil, err
	}
	return kc, nil
}

func (c *KubernetesClient) connect() (err error) {
	log.Printf("Using %s for kubernetes master", c.config.Host)

	options := v1.ListOptions{
		ResourceVersion: c.lastResourceVersion,
	}

	defer func() {
		if err != nil {
			c.stopWatchers()
		}
	}()

	ni := c.clientset.Core().Nodes()
	c.nodeWatcher, err = ni.Watch(options)
	if err != nil {
		return fmt.Errorf("couldn't watch events on nodes: %v", err)
	}

	si := c.clientset.Core().Services(api.NamespaceAll)
	c.serviceWatcher, err = si.Watch(options)
	if err != nil {
		return fmt.Errorf("couldn't watch events on services: %v", err)
	}

	ei := c.clientset.Core().Endpoints(api.NamespaceAll)
	c.endpointsWatcher, err = ei.Watch(options)
	if err != nil {
		return fmt.Errorf("couldn't watch events on endpoints: %v", err)
	}
	return
}

func (c *KubernetesClient) stopWatchers() {
	if c.nodeWatcher != nil {
		c.nodeWatcher.Stop()
	}
	if c.serviceWatcher != nil {
		c.serviceWatcher.Stop()
	}
	if c.endpointsWatcher != nil {
		c.endpointsWatcher.Stop()
	}
}

func (c *KubernetesClient) AddNotifier(n Notifier) {
	c.notifiers = append(c.notifiers, n)
}

func (c *KubernetesClient) Notify() {
	for _, n := range c.notifiers {
		if err := n.Notify(); err != nil {
			log.Printf("Couldn't notify: %s", err)
		}
	}
}

func (c *KubernetesClient) AddTemplate(t Template) {
	c.templates = append(c.templates, t)
}

func (c *KubernetesClient) ExecuteTemplates(info *ClusterInformation) {
	for _, t := range c.templates {
		if err := t.Execute(info); err != nil {
			log.Printf("Couldn't write template: %s", err)
		}
	}
}

func (c *KubernetesClient) readAnnotation(meta v1.ObjectMeta, annotation string, value interface{}) {
	data, ok := meta.Annotations[annotation]
	if ok && len(data) > 0 {
		err := json.Unmarshal([]byte(data), value)
		if err != nil {
			log.Printf("Couldn't parse %s annotation for %s service: %s", annotation, meta.Name, err)
		}
	}
}

func (c *KubernetesClient) getServices() ([]ServiceInformation, error) {
	services, err := c.serviceStore.List()
	if err != nil {
		return nil, fmt.Errorf("couldn't get services: %s", err)
	}

	endpoints, err := c.endpointsStore.List()
	if err != nil {
		return nil, fmt.Errorf("couldn't get endpoints: %s", err)
	}

	endpointsHelper := NewEndpointsHelper(endpoints)

	servicesInformation := make([]ServiceInformation, 0, len(services))
	for _, s := range services {
		var external []string
		if domains, ok := s.ObjectMeta.Annotations[ExternalDomainsAnnotation]; ok && len(domains) > 0 {
			external = strings.Split(domains, ",")
		}

		var portModes map[string]string
		c.readAnnotation(s.ObjectMeta, PortModeAnnotation, &portModes)

		var backendTimeouts map[string]int
		c.readAnnotation(s.ObjectMeta, BackendTimeoutAnnotation, &backendTimeouts)

		switch s.Spec.Type {
		case v1.ServiceTypeNodePort, v1.ServiceTypeLoadBalancer:
			endpointsPortsMap := endpointsHelper.ServicePortsMap(s)
			if len(endpointsPortsMap) == 0 {
				log.Printf("Couldn't find endpoints for %s in %s?", s.Name, s.Namespace)
				continue
			}

			for _, port := range s.Spec.Ports {
				mode, ok := portModes[port.Name]
				if !ok {
					mode = defaultPortMode
				}
				timeout, ok := backendTimeouts[port.Name]
				if !ok {
					timeout = 0
				}
				servicesInformation = append(servicesInformation,
					ServiceInformation{
						Name:      s.Name,
						Namespace: s.Namespace,
						Port: PortSpec{
							port.Port,
							strings.ToLower(mode),
							strings.ToLower(string(port.Protocol)),
						},
						Endpoints: endpointsPortsMap[port.TargetPort.IntVal],
						NodePort:  port.NodePort,
						External:  external,
						Timeout:   timeout,
					},
				)
			}
		}
	}
	return servicesInformation, nil
}

func (c *KubernetesClient) Update() error {
	nodeNames := c.nodeStore.GetNames()

	services, err := c.getServices()
	if err != nil {
		return fmt.Errorf("couldn't get services: %s", err)
	}

	portsMap := make(map[PortSpec]bool)
	for _, service := range services {
		portsMap[service.Port] = true
	}
	ports := make([]PortSpec, 0, len(portsMap))
	for port := range portsMap {
		ports = append(ports, port)
	}

	info := &ClusterInformation{
		Nodes:    nodeNames,
		Services: services,
		Ports:    ports,
		Domain:   c.domain,
	}
	c.ExecuteTemplates(info)
	c.Notify()

	return nil
}

func (c *KubernetesClient) Watch() error {
	isFirstUpdate := true
	updater := c.updaterBuilder(func() {
		var err error
		if err = c.Update(); err != nil {
			log.Printf("Couldn't update state: %s", err)
		}
		if isFirstUpdate {
			if err != nil {
				log.Fatalf("Failing on first update, check configuration.")
			}
			isFirstUpdate = false
		}
	})
	go updater.Run()

	c.nodeStore = NodeStore{NewLocalStore()}
	c.serviceStore = ServiceStore{NewLocalStore()}
	c.endpointsStore = EndpointsStore{NewLocalStore()}

	updateStore := func(s Store, e watch.Event) {
		if e.Object == nil {
			return
		}
		defer func() {
			accessor, _ := meta.Accessor(e.Object)
			c.lastResourceVersion = accessor.GetResourceVersion()
		}()

		switch e.Type {
		case watch.Added:
			s.Update(e.Object)
		case watch.Modified:
			old := s.Update(e.Object)
			if old == nil {
				log.Println("Modified unknown object, this shouldn't happen")
				break
			}
			eq, err := s.Equal(old, e.Object)
			if err != nil {
				log.Println(err)
				return
			}
			if eq {
				return
			}
		case watch.Deleted:
			s.Delete(e.Object)
		}
		updater.Signal()
	}

	var more bool
	var e watch.Event
	for {
		select {
		case e, more = <-c.nodeWatcher.ResultChan():
			updateStore(c.nodeStore, e)
		case e, more = <-c.serviceWatcher.ResultChan():
			updateStore(c.serviceStore, e)
		case e, more = <-c.endpointsWatcher.ResultChan():
			updateStore(c.endpointsStore, e)
		}

		// Used in tests to know when events have been processed
		if c.eventForwarder != nil {
			c.eventForwarder(e)
		}

		if !more {
			c.stopWatchers()
			log.Printf("Connection closed, trying to reconnect...")
			timeout := time.Duration(reconnectTimeoutSeconds) * time.Second
			err := wait.Poll(5*time.Second, timeout, func() (bool, error) {
				err := c.connect()
				if err != nil {
					log.Println(err)
				}
				return err == nil, nil
			})
			if err != nil {
				return err
			}
		}
	}
}
<commit_msg>Handle watch errors<commit_after>/*
Copyright 2016 Tuenti Technologies S.L. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"strings"
	"time"

	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/pkg/api"
	"k8s.io/client-go/pkg/api/meta"
	"k8s.io/client-go/pkg/api/unversioned"
	"k8s.io/client-go/pkg/api/v1"
	"k8s.io/client-go/pkg/util/wait"
	"k8s.io/client-go/pkg/watch"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
)

var defaultPortMode = "http"
var reconnectTimeoutSeconds = 300

func init() {
	flag.StringVar(&defaultPortMode, "default-port-mode", defaultPortMode, "Default mode for service ports")
	flag.IntVar(&reconnectTimeoutSeconds, "reconnect-timeout", reconnectTimeoutSeconds, "Reconnect timeout in seconds")
}

type KubernetesClient struct {
	config    *rest.Config
	clientset *kubernetes.Clientset

	nodeStore      NodeStore
	serviceStore   ServiceStore
	endpointsStore EndpointsStore

	nodeWatcher      watch.Interface
	serviceWatcher   watch.Interface
	endpointsWatcher watch.Interface

	lastResourceVersion string

	updaterBuilder UpdaterBuilder
	eventForwarder func(watch.Event)

	notifiers []Notifier
	templates []Template

	domain string
}

const (
	ExternalDomainsAnnotation = "kube2lb/external-domains"
	PortModeAnnotation        = "kube2lb/port-mode"
	BackendTimeoutAnnotation  = "kube2lb/backend-timeout"
)

func NewKubernetesClient(kubecfg, apiserver, domain string) (*KubernetesClient, error) {
	config, err := clientcmd.BuildConfigFromFlags(apiserver, kubecfg)
	if err != nil {
		return nil, err
	}

	clientset, err := kubernetes.NewForConfig(config)
	if err != nil {
		return nil, err
	}

	kc := &KubernetesClient{
		config:         config,
		clientset:      clientset,
		notifiers:      make([]Notifier, 0, 10),
		templates:      make([]Template, 0, 10),
		domain:         domain,
		updaterBuilder: NewUpdater,
	}

	if err := kc.connect(); err != nil {
		return nil, err
	}
	return kc, nil
}

func (c *KubernetesClient) connect() (err error) {
	log.Printf("Using %s for kubernetes master", c.config.Host)

	options := v1.ListOptions{
		ResourceVersion: c.lastResourceVersion,
	}

	defer func() {
		if err != nil {
			c.stopWatchers()
		}
	}()

	ni := c.clientset.Core().Nodes()
	c.nodeWatcher, err = ni.Watch(options)
	if err != nil {
		return fmt.Errorf("couldn't watch events on nodes: %v", err)
	}

	si := c.clientset.Core().Services(api.NamespaceAll)
	c.serviceWatcher, err = si.Watch(options)
	if err != nil {
		return fmt.Errorf("couldn't watch events on services: %v", err)
	}

	ei := c.clientset.Core().Endpoints(api.NamespaceAll)
	c.endpointsWatcher, err = ei.Watch(options)
	if err != nil {
		return fmt.Errorf("couldn't watch events on endpoints: %v", err)
	}
	return
}

func (c *KubernetesClient) stopWatchers() {
	if c.nodeWatcher != nil {
		c.nodeWatcher.Stop()
	}
	if c.serviceWatcher != nil {
		c.serviceWatcher.Stop()
	}
	if c.endpointsWatcher != nil {
		c.endpointsWatcher.Stop()
	}
}

func (c *KubernetesClient) AddNotifier(n Notifier) {
	c.notifiers = append(c.notifiers, n)
}

func (c *KubernetesClient) Notify() {
	for _, n := range c.notifiers {
		if err := n.Notify(); err != nil {
			log.Printf("Couldn't notify: %s", err)
		}
	}
}

func (c *KubernetesClient) AddTemplate(t Template) {
	c.templates = append(c.templates, t)
}

func (c *KubernetesClient) ExecuteTemplates(info *ClusterInformation) {
	for _, t := range c.templates {
		if err := t.Execute(info); err != nil {
			log.Printf("Couldn't write template: %s", err)
		}
	}
}

func (c *KubernetesClient) readAnnotation(meta v1.ObjectMeta, annotation string, value interface{}) {
	data, ok := meta.Annotations[annotation]
	if ok && len(data) > 0 {
		err := json.Unmarshal([]byte(data), value)
		if err != nil {
			log.Printf("Couldn't parse %s annotation for %s service: %s", annotation, meta.Name, err)
		}
	}
}

func (c *KubernetesClient) getServices() ([]ServiceInformation, error) {
	services, err := c.serviceStore.List()
	if err != nil {
		return nil, fmt.Errorf("couldn't get services: %s", err)
	}

	endpoints, err := c.endpointsStore.List()
	if err != nil {
		return nil, fmt.Errorf("couldn't get endpoints: %s", err)
	}

	endpointsHelper := NewEndpointsHelper(endpoints)

	servicesInformation := make([]ServiceInformation, 0, len(services))
	for _, s := range services {
		var external []string
		if domains, ok := s.ObjectMeta.Annotations[ExternalDomainsAnnotation]; ok && len(domains) > 0 {
			external = strings.Split(domains, ",")
		}

		var portModes map[string]string
		c.readAnnotation(s.ObjectMeta, PortModeAnnotation, &portModes)

		var backendTimeouts map[string]int
		c.readAnnotation(s.ObjectMeta, BackendTimeoutAnnotation, &backendTimeouts)

		switch s.Spec.Type {
		case v1.ServiceTypeNodePort, v1.ServiceTypeLoadBalancer:
			endpointsPortsMap := endpointsHelper.ServicePortsMap(s)
			if len(endpointsPortsMap) == 0 {
				log.Printf("Couldn't find endpoints for %s in %s?", s.Name, s.Namespace)
				continue
			}

			for _, port := range s.Spec.Ports {
				mode, ok := portModes[port.Name]
				if !ok {
					mode = defaultPortMode
				}
				timeout, ok := backendTimeouts[port.Name]
				if !ok {
					timeout = 0
				}
				servicesInformation = append(servicesInformation,
					ServiceInformation{
						Name:      s.Name,
						Namespace: s.Namespace,
						Port: PortSpec{
							port.Port,
							strings.ToLower(mode),
							strings.ToLower(string(port.Protocol)),
						},
						Endpoints: endpointsPortsMap[port.TargetPort.IntVal],
						NodePort:  port.NodePort,
						External:  external,
						Timeout:   timeout,
					},
				)
			}
		}
	}
	return servicesInformation, nil
}

func (c *KubernetesClient) Update() error {
	nodeNames := c.nodeStore.GetNames()

	services, err := c.getServices()
	if err != nil {
		return fmt.Errorf("couldn't get services: %s", err)
	}

	portsMap := make(map[PortSpec]bool)
	for _, service := range services {
		portsMap[service.Port] = true
	}
	ports := make([]PortSpec, 0, len(portsMap))
	for port := range portsMap {
		ports = append(ports, port)
	}

	info := &ClusterInformation{
		Nodes:    nodeNames,
		Services: services,
		Ports:    ports,
		Domain:   c.domain,
	}
	c.ExecuteTemplates(info)
	c.Notify()

	return nil
}

func (c *KubernetesClient) Watch() error {
	isFirstUpdate := true
	updater := c.updaterBuilder(func() {
		var err error
		if err = c.Update(); err != nil {
			log.Printf("Couldn't update state: %s", err)
		}
		if isFirstUpdate {
			if err != nil {
				log.Fatalf("Failing on first update, check configuration.")
			}
			isFirstUpdate = false
		}
	})
	go updater.Run()

	resetStores := func() {
		isFirstUpdate = true
		c.nodeStore = NodeStore{NewLocalStore()}
		c.serviceStore = ServiceStore{NewLocalStore()}
		c.endpointsStore = EndpointsStore{NewLocalStore()}
		c.lastResourceVersion = ""
	}
	resetStores()

	updateStore := func(s Store, e watch.Event) {
		switch e.Type {
		case watch.Added:
			s.Update(e.Object)
		case watch.Modified:
			old := s.Update(e.Object)
			if old == nil {
				log.Println("Modified unknown object, this shouldn't happen")
				break
			}
			eq, err := s.Equal(old, e.Object)
			if err != nil {
				log.Println(err)
				return
			}
			if eq {
				return
			}
		case watch.Deleted:
			s.Delete(e.Object)
		case watch.Error:
			status, ok := e.Object.(*unversioned.Status)
			if ok {
				log.Printf("Error received while watching: %s", status.Message)
			}
			log.Println("Local caches will be rebuilt")
			resetStores()
			return
		}
		accessor, _ := meta.Accessor(e.Object)
		if accessor != nil {
			c.lastResourceVersion = accessor.GetResourceVersion()
		}
		updater.Signal()
	}

	var more bool
	var e watch.Event
	for {
		select {
		case e, more = <-c.nodeWatcher.ResultChan():
			updateStore(c.nodeStore, e)
		case e, more = <-c.serviceWatcher.ResultChan():
			updateStore(c.serviceStore, e)
		case e, more = <-c.endpointsWatcher.ResultChan():
			updateStore(c.endpointsStore, e)
		}

		// Used in tests to know when events have been processed
		if c.eventForwarder != nil {
			c.eventForwarder(e)
		}

		if !more || e.Type == watch.Error {
			log.Printf("Connection closed, trying to reconnect...")
			timeout := time.Duration(reconnectTimeoutSeconds) * time.Second
			err := wait.Poll(5*time.Second, timeout, func() (bool, error) {
				err := c.connect()
				if err != nil {
					log.Println("Couldn't reconnect: ", err)
				}
				return err == nil, nil
			})
			if err != nil {
				return err
			}
		}
	}
}
<|endoftext|>


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

// Package stabilitytests contains long-running test cases verifying that otel-collector can run
// sustainably for long time, 1 hour by default.
// Tests supposed to be run on CircleCI, each tests must be allocated to exactly one runner
// to make sure that the whole test suit will not take longer than one hour.
// Because of that, every time overall number of stability tests changed,
// make sure to update CircleCI parameter: run-stability-tests.runners-number

package tests

import (
	"testing"
	"time"

	"go.opentelemetry.io/collector/testbed/testbed"
	scenarios "go.opentelemetry.io/collector/testbed/tests"

	"github.com/open-telemetry/opentelemetry-collector-contrib/testbed/datareceivers"
	"github.com/open-telemetry/opentelemetry-collector-contrib/testbed/datasenders"
)

var (
	contribPerfResultsSummary = &testbed.PerformanceResults{}
	resourceCheckPeriod, _    = time.ParseDuration("1m")
	processorsConfig          = map[string]string{
		"batch": `
  batch:
`,
	}
)

// TestMain is used to initiate setup, execution and tear down of testbed.
func TestMain(m *testing.M) {
	testbed.DoTestMain(m, contribPerfResultsSummary)
}

func TestStabilityTracesOpenCensus(t *testing.T) {
	scenarios.Scenario10kItemsPerSecond(
		t,
		testbed.NewOCTraceDataSender(testbed.DefaultHost, testbed.GetAvailablePort(t)),
		testbed.NewOCDataReceiver(testbed.GetAvailablePort(t)),
		testbed.ResourceSpec{
			ExpectedMaxCPU:      39,
			ExpectedMaxRAM:      90,
			ResourceCheckPeriod: resourceCheckPeriod,
		},
		contribPerfResultsSummary,
		processorsConfig,
		nil,
	)
}

func TestStabilityTracesSAPM(t *testing.T) {
	scenarios.Scenario10kItemsPerSecond(
		t,
		datasenders.NewSapmDataSender(testbed.GetAvailablePort(t)),
		datareceivers.NewSapmDataReceiver(testbed.GetAvailablePort(t)),
		testbed.ResourceSpec{
			ExpectedMaxCPU:      40,
			ExpectedMaxRAM:      100,
			ResourceCheckPeriod: resourceCheckPeriod,
		},
		contribPerfResultsSummary,
		processorsConfig,
		nil,
	)
}

func TestStabilityTracesOTLP(t *testing.T) {
	scenarios.Scenario10kItemsPerSecond(
		t,
		testbed.NewOTLPTraceDataSender(testbed.DefaultHost, testbed.GetAvailablePort(t)),
		testbed.NewOTLPDataReceiver(testbed.GetAvailablePort(t)),
		testbed.ResourceSpec{
			ExpectedMaxCPU:      20,
			ExpectedMaxRAM:      80,
			ResourceCheckPeriod: resourceCheckPeriod,
		},
		contribPerfResultsSummary,
		processorsConfig,
		nil,
	)
}

func TestStabilityTracesJaegerGRPC(t *testing.T) {
	scenarios.Scenario10kItemsPerSecond(
		t,
		testbed.NewJaegerGRPCDataSender(testbed.DefaultHost, testbed.GetAvailablePort(t)),
		testbed.NewJaegerDataReceiver(testbed.GetAvailablePort(t)),
		testbed.ResourceSpec{
			ExpectedMaxCPU:      40,
			ExpectedMaxRAM:      90,
			ResourceCheckPeriod: resourceCheckPeriod,
		},
		contribPerfResultsSummary,
		processorsConfig,
		nil,
	)
}

func TestStabilityTracesZipkin(t *testing.T) {
	scenarios.Scenario10kItemsPerSecond(
		t,
		testbed.NewZipkinDataSender(testbed.DefaultHost, testbed.GetAvailablePort(t)),
		testbed.NewZipkinDataReceiver(testbed.GetAvailablePort(t)),
		testbed.ResourceSpec{
			ExpectedMaxCPU:      80,
			ExpectedMaxRAM:      95,
			ResourceCheckPeriod: resourceCheckPeriod,
		},
		contribPerfResultsSummary,
		processorsConfig,
		nil,
	)
}
<commit_msg>Bump memory limits for TestStabilityTracesZipkin (#899)<commit_after>// Copyright 2020, OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package stabilitytests contains long-running test cases verifying that otel-collector can run
// sustainably for long time, 1 hour by default.
// Tests supposed to be run on CircleCI, each tests must be allocated to exactly one runner
// to make sure that the whole test suit will not take longer than one hour.
// Because of that, every time overall number of stability tests changed,
// make sure to update CircleCI parameter: run-stability-tests.runners-number

package tests

import (
	"testing"
	"time"

	"go.opentelemetry.io/collector/testbed/testbed"
	scenarios "go.opentelemetry.io/collector/testbed/tests"

	"github.com/open-telemetry/opentelemetry-collector-contrib/testbed/datareceivers"
	"github.com/open-telemetry/opentelemetry-collector-contrib/testbed/datasenders"
)

var (
	contribPerfResultsSummary = &testbed.PerformanceResults{}
	resourceCheckPeriod, _    = time.ParseDuration("1m")
	processorsConfig          = map[string]string{
		"batch": `
  batch:
`,
	}
)

// TestMain is used to initiate setup, execution and tear down of testbed.
func TestMain(m *testing.M) {
	testbed.DoTestMain(m, contribPerfResultsSummary)
}

func TestStabilityTracesOpenCensus(t *testing.T) {
	scenarios.Scenario10kItemsPerSecond(
		t,
		testbed.NewOCTraceDataSender(testbed.DefaultHost, testbed.GetAvailablePort(t)),
		testbed.NewOCDataReceiver(testbed.GetAvailablePort(t)),
		testbed.ResourceSpec{
			ExpectedMaxCPU:      39,
			ExpectedMaxRAM:      90,
			ResourceCheckPeriod: resourceCheckPeriod,
		},
		contribPerfResultsSummary,
		processorsConfig,
		nil,
	)
}

func TestStabilityTracesSAPM(t *testing.T) {
	scenarios.Scenario10kItemsPerSecond(
		t,
		datasenders.NewSapmDataSender(testbed.GetAvailablePort(t)),
		datareceivers.NewSapmDataReceiver(testbed.GetAvailablePort(t)),
		testbed.ResourceSpec{
			ExpectedMaxCPU:      40,
			ExpectedMaxRAM:      100,
			ResourceCheckPeriod: resourceCheckPeriod,
		},
		contribPerfResultsSummary,
		processorsConfig,
		nil,
	)
}

func TestStabilityTracesOTLP(t *testing.T) {
	scenarios.Scenario10kItemsPerSecond(
		t,
		testbed.NewOTLPTraceDataSender(testbed.DefaultHost, testbed.GetAvailablePort(t)),
		testbed.NewOTLPDataReceiver(testbed.GetAvailablePort(t)),
		testbed.ResourceSpec{
			ExpectedMaxCPU:      20,
			ExpectedMaxRAM:      80,
			ResourceCheckPeriod: resourceCheckPeriod,
		},
		contribPerfResultsSummary,
		processorsConfig,
		nil,
	)
}

func TestStabilityTracesJaegerGRPC(t *testing.T) {
	scenarios.Scenario10kItemsPerSecond(
		t,
		testbed.NewJaegerGRPCDataSender(testbed.DefaultHost, testbed.GetAvailablePort(t)),
		testbed.NewJaegerDataReceiver(testbed.GetAvailablePort(t)),
		testbed.ResourceSpec{
			ExpectedMaxCPU:      40,
			ExpectedMaxRAM:      90,
			ResourceCheckPeriod: resourceCheckPeriod,
		},
		contribPerfResultsSummary,
		processorsConfig,
		nil,
	)
}

func TestStabilityTracesZipkin(t *testing.T) {
	scenarios.Scenario10kItemsPerSecond(
		t,
		testbed.NewZipkinDataSender(testbed.DefaultHost, testbed.GetAvailablePort(t)),
		testbed.NewZipkinDataReceiver(testbed.GetAvailablePort(t)),
		testbed.ResourceSpec{
			ExpectedMaxCPU:      80,
			ExpectedMaxRAM:      110,
			ResourceCheckPeriod: resourceCheckPeriod,
		},
		contribPerfResultsSummary,
		processorsConfig,
		nil,
	)
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"os"
	"strings"

	"github.com/pachyderm/pachyderm/src/client"
	pfsclient "github.com/pachyderm/pachyderm/src/client/pfs"
	"github.com/pachyderm/pachyderm/src/client/pkg/discovery"
	"github.com/pachyderm/pachyderm/src/client/pkg/grpcutil"
	"github.com/pachyderm/pachyderm/src/client/pkg/shard"
	"github.com/pachyderm/pachyderm/src/client/pkg/uuid"
	ppsclient "github.com/pachyderm/pachyderm/src/client/pps" //SJ: bad name conflict w below
	"github.com/pachyderm/pachyderm/src/client/version"
	pfsmodel "github.com/pachyderm/pachyderm/src/server/pfs" // SJ: really bad name conflict. Normally I was making the non pfsclient stuff all under pfs server
	pfs_persist "github.com/pachyderm/pachyderm/src/server/pfs/db"
	"github.com/pachyderm/pachyderm/src/server/pfs/drive"
	pfs_server "github.com/pachyderm/pachyderm/src/server/pfs/server"
	"github.com/pachyderm/pachyderm/src/server/pkg/metrics"
	"github.com/pachyderm/pachyderm/src/server/pkg/netutil"
	ppsserver "github.com/pachyderm/pachyderm/src/server/pps" //SJ: cant name this server per the refactor convention because of the import below
	"github.com/pachyderm/pachyderm/src/server/pps/persist"
	persist_server "github.com/pachyderm/pachyderm/src/server/pps/persist/server"
	pps_server "github.com/pachyderm/pachyderm/src/server/pps/server"

	flag "github.com/spf13/pflag"
	"go.pedge.io/env"
	"go.pedge.io/lion/proto"
	"go.pedge.io/proto/server"
	"google.golang.org/grpc"
	"k8s.io/kubernetes/pkg/api"
	kube_client "k8s.io/kubernetes/pkg/client/restclient"
	kube "k8s.io/kubernetes/pkg/client/unversioned"
)

var readinessCheck bool

func init() {
	flag.BoolVar(&readinessCheck, "readiness-check", false, "Set to true when checking if local pod is ready")
	flag.Parse()
}

type appEnv struct {
	Port            uint16 `env:"PORT,default=650"`
	NumShards       uint64 `env:"NUM_SHARDS,default=32"`
	StorageRoot     string `env:"PACH_ROOT,required"`
	StorageBackend  string `env:"STORAGE_BACKEND,default="`
	DatabaseAddress string `env:"RETHINK_PORT_28015_TCP_ADDR,required"`
	DatabaseName    string `env:"DATABASE_NAME,default=pachyderm"`
	KubeAddress     string `env:"KUBERNETES_PORT_443_TCP_ADDR,required"`
	EtcdAddress     string `env:"ETCD_PORT_2379_TCP_ADDR,required"`
	Namespace       string `env:"NAMESPACE,default=default"`
	Metrics         bool   `env:"METRICS,default=true"`
	Init            bool   `env:"INIT,default=false"`
}

func main() {
	env.Main(do, &appEnv{})
}

func do(appEnvObj interface{}) error {
	appEnv := appEnvObj.(*appEnv)
	etcdClient := getEtcdClient(appEnv)
	if appEnv.Init {
		if err := setClusterID(etcdClient); err != nil {
			return fmt.Errorf("error connecting to etcd, if this error persists it likely indicates that kubernetes services are not working correctly. See https://github.com/pachyderm/pachyderm/blob/master/SETUP.md#pachd-or-pachd-init-crash-loop-with-error-connecting-to-etcd for more info")
		}
		if err := persist_server.InitDBs(fmt.Sprintf("%s:28015", appEnv.DatabaseAddress), appEnv.DatabaseName); err != nil {
			return err
		}
		rethinkAddress := fmt.Sprintf("%s:28015", appEnv.DatabaseAddress)
		return pfs_persist.InitDB(rethinkAddress, appEnv.DatabaseName)
	}
	if readinessCheck {
		//c, err := client.NewInCluster()
		c, err := client.NewFromAddress("127.0.0.1:650")
		if err != nil {
			return err
		}

		// We want to use a PPS API instead of a PFS API because PFS APIs
		// typically talk to every node, but the point of the readiness probe
		// is that it checks to see if this particular node is functioning,
		// and removing it from the service if it's not.  So if we use a PFS
		// API such as ListRepo for readiness probe, then the failure of any
		// node will result in the failures of all readiness probes, causing
		// all nodes to be removed from the pachd service.
		_, err = c.ListPipeline()
		if err != nil {
			return err
		}

		os.Exit(0)

		return nil
	}

	clusterID, err := getClusterID(etcdClient)
	if err != nil {
		return err
	}
	kubeClient, err := getKubeClient(appEnv)
	if err != nil {
		return err
	}
	if appEnv.Metrics {
		go metrics.ReportMetrics(clusterID, kubeClient)
	}
	rethinkAPIServer, err := getRethinkAPIServer(appEnv)
	if err != nil {
		return err
	}
	address, err := netutil.ExternalIP()
	if err != nil {
		return err
	}
	address = fmt.Sprintf("%s:%d", address, appEnv.Port)
	sharder := shard.NewSharder(
		etcdClient,
		appEnv.NumShards,
		appEnv.Namespace,
	)
	go func() {
		if err := sharder.AssignRoles(address, nil); err != nil {
			protolion.Printf("error from sharder.AssignRoles: %s", sanitizeErr(err))
		}
	}()
	driver, err := getPFSDriver(address, appEnv)
	//	driver, err := drive.NewDriver(address)
	if err != nil {
		return err
	}
	apiServer := pfs_server.NewAPIServer(
		pfsmodel.NewHasher(
			appEnv.NumShards,
			1,
		),
		shard.NewRouter(
			sharder,
			grpcutil.NewDialer(
				grpc.WithInsecure(),
			),
			address,
		),
	)
	go func() {
		if err := sharder.RegisterFrontends(nil, address, []shard.Frontend{apiServer}); err != nil {
			protolion.Printf("error from sharder.RegisterFrontend %s", sanitizeErr(err))
		}
	}()
	internalAPIServer := pfs_server.NewInternalAPIServer(
		pfsmodel.NewHasher(
			appEnv.NumShards,
			1,
		),
		shard.NewRouter(
			sharder,
			grpcutil.NewDialer(
				grpc.WithInsecure(),
			),
			address,
		),
		driver,
	)
	ppsAPIServer := pps_server.NewAPIServer(
		ppsserver.NewHasher(appEnv.NumShards, appEnv.NumShards),
		address,
		kubeClient,
		getNamespace(),
	)
	go func() {
		if err := sharder.Register(nil, address, []shard.Server{internalAPIServer, ppsAPIServer}); err != nil {
			protolion.Printf("error from sharder.Register %s", sanitizeErr(err))
		}
	}()
	blockAPIServer, err := pfs_server.NewBlockAPIServer(appEnv.StorageRoot, appEnv.StorageBackend)
	if err != nil {
		return err
	}
	return protoserver.Serve(
		func(s *grpc.Server) {
			pfsclient.RegisterAPIServer(s, apiServer)
			pfsclient.RegisterInternalAPIServer(s, internalAPIServer)
			pfsclient.RegisterBlockAPIServer(s, blockAPIServer)
			ppsclient.RegisterAPIServer(s, ppsAPIServer)
			ppsserver.RegisterInternalJobAPIServer(s, ppsAPIServer)
			persist.RegisterAPIServer(s, rethinkAPIServer)
		},
		protoserver.ServeOptions{
			Version: version.Version,
		},
		protoserver.ServeEnv{
			GRPCPort: appEnv.Port,
		},
	)
}

func getEtcdClient(env *appEnv) discovery.Client {
	return discovery.NewEtcdClient(fmt.Sprintf("http://%s:2379", env.EtcdAddress))
}

const clusterIDKey = "cluster-id"

func setClusterID(client discovery.Client) error {
	return client.Set(clusterIDKey, uuid.NewWithoutDashes(), 0)
}

func getClusterID(client discovery.Client) (string, error) {
	id, err := client.Get(clusterIDKey)
	if err != nil {
		return "", err
	}
	if id == "" {
		return "", fmt.Errorf("clusterID not yet set")
	}
	return id, nil
}

func getKubeClient(env *appEnv) (*kube.Client, error) {
	kubeClient, err := kube.NewInCluster()
	if err != nil {
		protolion.Errorf("falling back to insecure kube client due to error from NewInCluster: %s", sanitizeErr(err))
	} else {
		return kubeClient, err
	}
	config := &kube_client.Config{
		Host:     fmt.Sprintf("%s:443", env.KubeAddress),
		Insecure: true,
	}
	return kube.New(config)
}

func getPFSDriver(address string, env *appEnv) (drive.Driver, error) {
	rethinkAddress := fmt.Sprintf("%s:28015", env.DatabaseAddress)
	return pfs_persist.NewDriver(address, rethinkAddress, env.DatabaseName)
}

func getRethinkAPIServer(env *appEnv) (persist.APIServer, error) {
	if err := persist_server.CheckDBs(fmt.Sprintf("%s:28015", env.DatabaseAddress), env.DatabaseName); err != nil {
		return nil, err
	}
	return persist_server.NewRethinkAPIServer(fmt.Sprintf("%s:28015", env.DatabaseAddress), env.DatabaseName)
}

// getNamespace returns the kubernetes namespace that this pachd pod runs in
func getNamespace() string {
	namespace := os.Getenv("PACHD_POD_NAMESPACE")
	if namespace != "" {
		return namespace
	}
	return api.NamespaceDefault
}

func sanitizeErr(err error) error {
	if err == nil {
		return nil
	}

	return errors.New(grpc.ErrorDesc(err))
}
<commit_msg>Fix compile error<commit_after>package main

import (
	"errors"
	"fmt"
	"os"

	"github.com/pachyderm/pachyderm/src/client"
	pfsclient "github.com/pachyderm/pachyderm/src/client/pfs"
	"github.com/pachyderm/pachyderm/src/client/pkg/discovery"
	"github.com/pachyderm/pachyderm/src/client/pkg/grpcutil"
	"github.com/pachyderm/pachyderm/src/client/pkg/shard"
	"github.com/pachyderm/pachyderm/src/client/pkg/uuid"
	ppsclient "github.com/pachyderm/pachyderm/src/client/pps" //SJ: bad name conflict w below
	"github.com/pachyderm/pachyderm/src/client/version"
	pfsmodel "github.com/pachyderm/pachyderm/src/server/pfs" // SJ: really bad name conflict. Normally I was making the non pfsclient stuff all under pfs server
	pfs_persist "github.com/pachyderm/pachyderm/src/server/pfs/db"
	"github.com/pachyderm/pachyderm/src/server/pfs/drive"
	pfs_server "github.com/pachyderm/pachyderm/src/server/pfs/server"
	"github.com/pachyderm/pachyderm/src/server/pkg/metrics"
	"github.com/pachyderm/pachyderm/src/server/pkg/netutil"
	ppsserver "github.com/pachyderm/pachyderm/src/server/pps" //SJ: cant name this server per the refactor convention because of the import below
	"github.com/pachyderm/pachyderm/src/server/pps/persist"
	persist_server "github.com/pachyderm/pachyderm/src/server/pps/persist/server"
	pps_server "github.com/pachyderm/pachyderm/src/server/pps/server"

	flag "github.com/spf13/pflag"
	"go.pedge.io/env"
	"go.pedge.io/lion/proto"
	"go.pedge.io/proto/server"
	"google.golang.org/grpc"
	"k8s.io/kubernetes/pkg/api"
	kube_client "k8s.io/kubernetes/pkg/client/restclient"
	kube "k8s.io/kubernetes/pkg/client/unversioned"
)

var readinessCheck bool

func init() {
	flag.BoolVar(&readinessCheck, "readiness-check", false, "Set to true when checking if local pod is ready")
	flag.Parse()
}

type appEnv struct {
	Port            uint16 `env:"PORT,default=650"`
	NumShards       uint64 `env:"NUM_SHARDS,default=32"`
	StorageRoot     string `env:"PACH_ROOT,required"`
	StorageBackend  string `env:"STORAGE_BACKEND,default="`
	DatabaseAddress string `env:"RETHINK_PORT_28015_TCP_ADDR,required"`
	DatabaseName    string `env:"DATABASE_NAME,default=pachyderm"`
	KubeAddress     string `env:"KUBERNETES_PORT_443_TCP_ADDR,required"`
	EtcdAddress     string `env:"ETCD_PORT_2379_TCP_ADDR,required"`
	Namespace       string `env:"NAMESPACE,default=default"`
	Metrics         bool   `env:"METRICS,default=true"`
	Init            bool   `env:"INIT,default=false"`
}

func main() {
	env.Main(do, &appEnv{})
}

func do(appEnvObj interface{}) error {
	appEnv := appEnvObj.(*appEnv)
	etcdClient := getEtcdClient(appEnv)
	if appEnv.Init {
		if err := setClusterID(etcdClient); err != nil {
			return fmt.Errorf("error connecting to etcd, if this error persists it likely indicates that kubernetes services are not working correctly. See https://github.com/pachyderm/pachyderm/blob/master/SETUP.md#pachd-or-pachd-init-crash-loop-with-error-connecting-to-etcd for more info")
		}
		if err := persist_server.InitDBs(fmt.Sprintf("%s:28015", appEnv.DatabaseAddress), appEnv.DatabaseName); err != nil {
			return err
		}
		rethinkAddress := fmt.Sprintf("%s:28015", appEnv.DatabaseAddress)
		return pfs_persist.InitDB(rethinkAddress, appEnv.DatabaseName)
	}
	if readinessCheck {
		//c, err := client.NewInCluster()
		c, err := client.NewFromAddress("127.0.0.1:650")
		if err != nil {
			return err
		}

		// We want to use a PPS API instead of a PFS API because PFS APIs
		// typically talk to every node, but the point of the readiness probe
		// is that it checks to see if this particular node is functioning,
		// and removing it from the service if it's not.  So if we use a PFS
		// API such as ListRepo for readiness probe, then the failure of any
		// node will result in the failures of all readiness probes, causing
		// all nodes to be removed from the pachd service.
		_, err = c.ListPipeline()
		if err != nil {
			return err
		}

		os.Exit(0)

		return nil
	}

	clusterID, err := getClusterID(etcdClient)
	if err != nil {
		return err
	}
	kubeClient, err := getKubeClient(appEnv)
	if err != nil {
		return err
	}
	if appEnv.Metrics {
		go metrics.ReportMetrics(clusterID, kubeClient)
	}
	rethinkAPIServer, err := getRethinkAPIServer(appEnv)
	if err != nil {
		return err
	}
	address, err := netutil.ExternalIP()
	if err != nil {
		return err
	}
	address = fmt.Sprintf("%s:%d", address, appEnv.Port)
	sharder := shard.NewSharder(
		etcdClient,
		appEnv.NumShards,
		appEnv.Namespace,
	)
	go func() {
		if err := sharder.AssignRoles(address, nil); err != nil {
			protolion.Printf("error from sharder.AssignRoles: %s", sanitizeErr(err))
		}
	}()
	driver, err := getPFSDriver(address, appEnv)
	//	driver, err := drive.NewDriver(address)
	if err != nil {
		return err
	}
	apiServer := pfs_server.NewAPIServer(
		pfsmodel.NewHasher(
			appEnv.NumShards,
			1,
		),
		shard.NewRouter(
			sharder,
			grpcutil.NewDialer(
				grpc.WithInsecure(),
			),
			address,
		),
	)
	go func() {
		if err := sharder.RegisterFrontends(nil, address, []shard.Frontend{apiServer}); err != nil {
			protolion.Printf("error from sharder.RegisterFrontend %s", sanitizeErr(err))
		}
	}()
	internalAPIServer := pfs_server.NewInternalAPIServer(
		pfsmodel.NewHasher(
			appEnv.NumShards,
			1,
		),
		shard.NewRouter(
			sharder,
			grpcutil.NewDialer(
				grpc.WithInsecure(),
			),
			address,
		),
		driver,
	)
	ppsAPIServer := pps_server.NewAPIServer(
		ppsserver.NewHasher(appEnv.NumShards, appEnv.NumShards),
		address,
		kubeClient,
		getNamespace(),
	)
	go func() {
		if err := sharder.Register(nil, address, []shard.Server{internalAPIServer, ppsAPIServer}); err != nil {
			protolion.Printf("error from sharder.Register %s", sanitizeErr(err))
		}
	}()
	blockAPIServer, err := pfs_server.NewBlockAPIServer(appEnv.StorageRoot, appEnv.StorageBackend)
	if err != nil {
		return err
	}
	return protoserver.Serve(
		func(s *grpc.Server) {
			pfsclient.RegisterAPIServer(s, apiServer)
			pfsclient.RegisterInternalAPIServer(s, internalAPIServer)
			pfsclient.RegisterBlockAPIServer(s, blockAPIServer)
			ppsclient.RegisterAPIServer(s, ppsAPIServer)
			ppsserver.RegisterInternalJobAPIServer(s, ppsAPIServer)
			persist.RegisterAPIServer(s, rethinkAPIServer)
		},
		protoserver.ServeOptions{
			Version: version.Version,
		},
		protoserver.ServeEnv{
			GRPCPort: appEnv.Port,
		},
	)
}

func getEtcdClient(env *appEnv) discovery.Client {
	return discovery.NewEtcdClient(fmt.Sprintf("http://%s:2379", env.EtcdAddress))
}

const clusterIDKey = "cluster-id"

func setClusterID(client discovery.Client) error {
	return client.Set(clusterIDKey, uuid.NewWithoutDashes(), 0)
}

func getClusterID(client discovery.Client) (string, error) {
	id, err := client.Get(clusterIDKey)
	if err != nil {
		return "", err
	}
	if id == "" {
		return "", fmt.Errorf("clusterID not yet set")
	}
	return id, nil
}

func getKubeClient(env *appEnv) (*kube.Client, error) {
	kubeClient, err := kube.NewInCluster()
	if err != nil {
		protolion.Errorf("falling back to insecure kube client due to error from NewInCluster: %s", sanitizeErr(err))
	} else {
		return kubeClient, err
	}
	config := &kube_client.Config{
		Host:     fmt.Sprintf("%s:443", env.KubeAddress),
		Insecure: true,
	}
	return kube.New(config)
}

func getPFSDriver(address string, env *appEnv) (drive.Driver, error) {
	rethinkAddress := fmt.Sprintf("%s:28015", env.DatabaseAddress)
	return pfs_persist.NewDriver(address, rethinkAddress, env.DatabaseName)
}

func getRethinkAPIServer(env *appEnv) (persist.APIServer, error) {
	if err := persist_server.CheckDBs(fmt.Sprintf("%s:28015", env.DatabaseAddress), env.DatabaseName); err != nil {
		return nil, err
	}
	return persist_server.NewRethinkAPIServer(fmt.Sprintf("%s:28015", env.DatabaseAddress), env.DatabaseName)
}

// getNamespace returns the kubernetes namespace that this pachd pod runs in
func getNamespace() string {
	namespace := os.Getenv("PACHD_POD_NAMESPACE")
	if namespace != "" {
		return namespace
	}
	return api.NamespaceDefault
}

func sanitizeErr(err error) error {
	if err == nil {
		return nil
	}

	return errors.New(grpc.ErrorDesc(err))
}
<|endoftext|>


<commit_before>package lclip

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"reflect"
	"sort"
	"testing"

	"github.com/mitchellh/go-homedir"
)

var tempPath string

func TestMain(m *testing.M) {
	f, err := ioutil.TempFile(os.TempDir(), "test")
	if err != nil {
		fmt.Fprintln(os.Stderr, "lclip_test:", err)
		return
	}
	f.Close()
	tempPath = f.Name()

	e := m.Run()
	defer os.Exit(e)

	os.Remove(tempPath)
}

func TestDefaultPath(t *testing.T) {
	h, err := homedir.Dir()
	if err != nil {
		t.Fatal(err)
	}
	expect := filepath.Join(h, ".lclip.db")
	actual, err := DefaultPath()
	if err != nil {
		t.Errorf("DefaultPath returns %q; want nil", err)
	}
	if actual != expect {
		t.Errorf("DefaultPath = %q; want %q",
			actual, expect)
	}
}

func TestNewWithDefaultPath(t *testing.T) {
	h, err := homedir.Dir()
	if err != nil {
		t.Fatal(err)
	}

	c, err := NewClipboardWithDefaultPath()
	if err != nil {
		t.Fatal(err)
	}
	expect := filepath.Join(h, ".lclip.db")
	actual := c.Path()
	if actual != expect {
		t.Errorf("DefaultPath = %q; want %q",
			actual, expect)
	}
}

func TestCreateStorageFileIfNotExists(t *testing.T) {
	os.Remove(tempPath)

	c, err := NewClipboard(tempPath)
	if err != nil {
		t.Fatal(err)
	}
	defer c.Close()

	if _, err := os.Stat(tempPath); err != nil {
		t.Error("not create storage file; want create")
	}
}

type AccessTest struct {
	Label string
	Data  []byte
}

var indexTestsAccess = []AccessTest{
	{Label: "foo", Data: []byte("bar")},
	{Label: "hoge", Data: []byte("piyo")},
	{Label: "日本語", Data: []byte("日本語")},
}

func TestSetText(t *testing.T) {
	os.Remove(tempPath)

	c, err := NewClipboard(tempPath)
	if err != nil {
		t.Fatal(err)
	}
	defer c.Close()
	for _, test := range indexTestsAccess {
		if err = c.Set(test.Label, test.Data); err != nil {
			t.Error("Set(%q) returns %q; want nil",
				test.Label, err)
		}
		expect := test.Data
		actual, err := c.Get(test.Label)
		if err != nil {
			t.Error("Get(%q) returns %q; want nil",
				test.Label, err)
		}
		if !reflect.DeepEqual(actual, expect) {
			t.Errorf("after Set(%q, %q), Get(%q) = %q; want %q",
				test.Label, test.Data,
				test.Label, actual, expect)
		}
	}
}

var indexTestsLabels = [][]string{
	{"foo", "bar", "baz"},
	{"hoge", "piyo", "fuga"},
}

func TestListLabels(t *testing.T) {
	for _, labels := range indexTestsLabels {
		os.Remove(tempPath)

		c, err := NewClipboard(tempPath)
		if err != nil {
			t.Fatal(err)
		}
		for _, label := range labels {
			if err = c.Set(label, []byte(``)); err != nil {
				t.Fatal(err)
			}
		}

		expect := append(make([]string, 0, len(labels)), labels...)
		actual := c.Labels()
		sort.Strings(expect)
		sort.Strings(actual)
		if !reflect.DeepEqual(actual, expect) {
			t.Errorf("got %q; want %q", actual, expect)
		}
		if err := c.Close(); err != nil {
			t.Fatal(err)
		}
	}
}

func TestSave(t *testing.T) {
	os.Remove(tempPath)

	{
		c, err := NewClipboard(tempPath)
		if err != nil {
			t.Fatal(err)
		}
		for _, test := range indexTestsAccess {
			if err := c.Set(test.Label, test.Data); err != nil {
				t.Fatal(err)
			}
		}
		if err := c.Close(); err != nil {
			t.Fatal(err)
		}
	}
	{
		c, err := NewClipboard(tempPath)
		if err != nil {
			t.Fatal(err)
		}
		defer c.Close()
		for _, test := range indexTestsAccess {
			expect := test.Data
			actual, err := c.Get(test.Label)
			if err != nil {
				t.Fatal(err)
			}
			if !reflect.DeepEqual(actual, expect) {
				t.Errorf("Get(%q) = %q; want %q",
					test.Label, actual, expect)
			}
		}
	}
}
<commit_msg>Remove TestNewWithDefaultPath which affect home<commit_after>package lclip

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"reflect"
	"sort"
	"testing"

	"github.com/mitchellh/go-homedir"
)

var tempPath string

func TestMain(m *testing.M) {
	f, err := ioutil.TempFile(os.TempDir(), "test")
	if err != nil {
		fmt.Fprintln(os.Stderr, "lclip_test:", err)
		return
	}
	f.Close()
	tempPath = f.Name()

	e := m.Run()
	defer os.Exit(e)

	os.Remove(tempPath)
}

func TestDefaultPath(t *testing.T) {
	h, err := homedir.Dir()
	if err != nil {
		t.Fatal(err)
	}
	expect := filepath.Join(h, ".lclip.db")
	actual, err := DefaultPath()
	if err != nil {
		t.Errorf("DefaultPath returns %q; want nil", err)
	}
	if actual != expect {
		t.Errorf("DefaultPath = %q; want %q",
			actual, expect)
	}
}

func TestCreateStorageFileIfNotExists(t *testing.T) {
	os.Remove(tempPath)

	c, err := NewClipboard(tempPath)
	if err != nil {
		t.Fatal(err)
	}
	defer c.Close()

	if _, err := os.Stat(tempPath); err != nil {
		t.Error("not create storage file; want create")
	}
}

type AccessTest struct {
	Label string
	Data  []byte
}

var indexTestsAccess = []AccessTest{
	{Label: "foo", Data: []byte("bar")},
	{Label: "hoge", Data: []byte("piyo")},
	{Label: "日本語", Data: []byte("日本語")},
}

func TestSetText(t *testing.T) {
	os.Remove(tempPath)

	c, err := NewClipboard(tempPath)
	if err != nil {
		t.Fatal(err)
	}
	defer c.Close()
	for _, test := range indexTestsAccess {
		if err = c.Set(test.Label, test.Data); err != nil {
			t.Error("Set(%q) returns %q; want nil",
				test.Label, err)
		}
		expect := test.Data
		actual, err := c.Get(test.Label)
		if err != nil {
			t.Error("Get(%q) returns %q; want nil",
				test.Label, err)
		}
		if !reflect.DeepEqual(actual, expect) {
			t.Errorf("after Set(%q, %q), Get(%q) = %q; want %q",
				test.Label, test.Data,
				test.Label, actual, expect)
		}
	}
}

var indexTestsLabels = [][]string{
	{"foo", "bar", "baz"},
	{"hoge", "piyo", "fuga"},
}

func TestListLabels(t *testing.T) {
	for _, labels := range indexTestsLabels {
		os.Remove(tempPath)

		c, err := NewClipboard(tempPath)
		if err != nil {
			t.Fatal(err)
		}
		for _, label := range labels {
			if err = c.Set(label, []byte(``)); err != nil {
				t.Fatal(err)
			}
		}

		expect := append(make([]string, 0, len(labels)), labels...)
		actual := c.Labels()
		sort.Strings(expect)
		sort.Strings(actual)
		if !reflect.DeepEqual(actual, expect) {
			t.Errorf("got %q; want %q", actual, expect)
		}
		if err := c.Close(); err != nil {
			t.Fatal(err)
		}
	}
}

func TestSave(t *testing.T) {
	os.Remove(tempPath)

	{
		c, err := NewClipboard(tempPath)
		if err != nil {
			t.Fatal(err)
		}
		for _, test := range indexTestsAccess {
			if err := c.Set(test.Label, test.Data); err != nil {
				t.Fatal(err)
			}
		}
		if err := c.Close(); err != nil {
			t.Fatal(err)
		}
	}
	{
		c, err := NewClipboard(tempPath)
		if err != nil {
			t.Fatal(err)
		}
		defer c.Close()
		for _, test := range indexTestsAccess {
			expect := test.Data
			actual, err := c.Get(test.Label)
			if err != nil {
				t.Fatal(err)
			}
			if !reflect.DeepEqual(actual, expect) {
				t.Errorf("Get(%q) = %q; want %q",
					test.Label, actual, expect)
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/MJKWoolnough/gopherjs/xjs"
	"honnef.co/go/js/dom"
)

func add(c dom.Element) {
	u := xjs.CreateElement("input")
	u.SetAttribute("value", "Upload")
	u.SetAttribute("type", "button")
	u.AddEventListener("click", false, func(dom.Event) {
		xjs.RemoveChildren(c)
		upload(c)
	})
	d := xjs.CreateElement("input")
	d.SetAttribute("value", "Download")
	d.SetAttribute("type", "button")
	d.AddEventListener("click", false, func(dom.Event) {
		xjs.RemoveChildren(c)
		download(c)
	})
	g := xjs.CreateElement("input")
	g.SetAttribute("value", "Generate")
	g.SetAttribute("type", "button")
	g.AddEventListener("click", false, func(dom.Event) {
		xjs.RemoveChildren(c)
		generate(c)
	})
	c.AppendChild(u)
	c.AppendChild(d)
	c.AppendChild(g)
}

func upload(c dom.Element) {

}

func download(c dom.Element) {

}
<commit_msg>Removed redundent file<commit_after><|endoftext|>


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

package events

import (
	"testing"
	"time"

	"istio.io/istio/galley/pkg/runtime/resource"
	"istio.io/istio/pkg/test/util/retry"
)

const (
	DefaultTimeout = 2 * time.Second
	DefaultPeriod  = 100 * time.Millisecond
)

var (
	defaultOptions = []retry.Option{retry.Timeout(DefaultTimeout), retry.Delay(DefaultPeriod)}
)

// ChannelHandler creates an EventHandler that adds the event to the provided channel.
func ChannelHandler(ch chan resource.Event) resource.EventHandler {
	return func(e resource.Event) {
		ch <- e
	}
}

// ExpectOne polls the channel and ensures that only a single event is available. Fails the test
// if the number of events != 1.
func ExpectOne(t *testing.T, ch chan resource.Event, options ...retry.Option) resource.Event {
	t.Helper()
	e := Expect(t, ch, options...)

	// Use the default options for checking for none. This is to avoid long delays when the caller
	// increases the polling timeout.
	ExpectNone(t, ch, defaultOptions...)
	return e
}

// Expect polls the channel for the next event and returns it. Fails the test if no event found.
func Expect(t *testing.T, ch chan resource.Event, options ...retry.Option) resource.Event {
	t.Helper()

	e := Poll(ch, options...)
	if e == nil {
		t.Fatalf("timed out waiting for event")
	}
	return *e
}

// ExpectNone polls the channel and fails the test if any events are available.
func ExpectNone(t *testing.T, ch chan resource.Event, options ...retry.Option) {
	t.Helper()
	e := Poll(ch, options...)
	if e != nil {
		t.Fatalf("expected no events, found: %v", e)
	}
}

// Poll polls the channel to see if there is an event waiting. Returns either the next event or nil.
func Poll(ch chan resource.Event, options ...retry.Option) *resource.Event {
	// Add the default options first, then the arguments (if provided). Since options are applied
	// in-order, this allows the defaults to be overridden.
	options = append(append([]retry.Option{}, defaultOptions...), options...)
	e, err := retry.Do(func() (result interface{}, completed bool, err error) {
		select {
		case e := <-ch:
			return &e, true, nil
		default:
			return nil, false, nil
		}
	}, options...)

	if err != nil {
		return nil
	}

	return e.(*resource.Event)
}
<commit_msg>Add longer timeouts for Galley tests. (#11517)<commit_after>// Copyright 2019 Istio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package events

import (
	"testing"
	"time"

	"istio.io/istio/galley/pkg/runtime/resource"
	"istio.io/istio/pkg/test/util/retry"
)

const (
	defaultPositiveTimeout = 10 * time.Second
	defaultNegativeTimeout = 3 * time.Second
	defaultRetryPeriod     = 100 * time.Millisecond
)

var (
	defaultPositiveOptions = []retry.Option{retry.Timeout(defaultPositiveTimeout), retry.Delay(defaultRetryPeriod)}
	defaultNegativeOptions = []retry.Option{retry.Timeout(defaultNegativeTimeout), retry.Delay(defaultRetryPeriod)}
)

// ChannelHandler creates an EventHandler that adds the event to the provided channel.
func ChannelHandler(ch chan resource.Event) resource.EventHandler {
	return func(e resource.Event) {
		ch <- e
	}
}

// ExpectOne polls the channel and ensures that only a single event is available. Fails the test
// if the number of events != 1.
func ExpectOne(t *testing.T, ch chan resource.Event, options ...retry.Option) resource.Event {
	t.Helper()
	e := Expect(t, ch, options...)

	// Use the default options for checking for none. This is to avoid long delays when the caller
	// increases the polling timeout.
	ExpectNone(t, ch, options...)
	return e
}

// Expect polls the channel for the next event and returns it. Fails the test if no event found.
func Expect(t *testing.T, ch chan resource.Event, options ...retry.Option) resource.Event {
	t.Helper()

	// Add sensible default retry options for assumed success, but let caller override.
	options = concat(options, defaultPositiveOptions)

	e := Poll(ch, options...)
	if e == nil {
		t.Fatalf("timed out waiting for event")
	}
	return *e
}

// ExpectNone polls the channel and fails the test if any events are available.
func ExpectNone(t *testing.T, ch chan resource.Event, options ...retry.Option) {
	t.Helper()

	// Add sensible default retry options for assumed failure, but let caller override.
	options = concat(options, defaultNegativeOptions)

	e := Poll(ch, options...)
	if e != nil {
		t.Fatalf("expected no events, found: %v", e)
	}
}

// Poll polls the channel to see if there is an event waiting. Returns either the next event or nil.
func Poll(ch chan resource.Event, options ...retry.Option) *resource.Event {
	e, err := retry.Do(func() (result interface{}, completed bool, err error) {
		select {
		case e := <-ch:
			return &e, true, nil
		default:
			return nil, false, nil
		}
	}, options...)

	if err != nil {
		return nil
	}

	return e.(*resource.Event)
}

func concat(part1 []retry.Option, part2 []retry.Option) []retry.Option {
	return append(append([]retry.Option{}, part1...), part2...)
}
<|endoftext|>


<commit_before>package main

import (
	"../libs/twodee"
	"time"
)

type DirectionsHistoryEntry struct {
	prev, next *DirectionsHistoryEntry
	dir        MoveDirection
}

type DirectionsHistory struct {
	tail       *DirectionsHistoryEntry
	directions []*DirectionsHistoryEntry
}

// Adds a MoveDirection to the history if it's not already present.
func (dh *DirectionsHistory) Add(d MoveDirection) {
	entry := dh.directions[d]
	if entry.prev == nil && entry.next == nil && entry != dh.tail {
		if dh.tail != nil {
			dh.tail.next = entry
			entry.prev = dh.tail
		}
		dh.tail = entry
	}
}

// Removes a particular MoveDirection from the history chain; sets its prev and next fields to nil. Resets dh's tail if necessary.
func (dh *DirectionsHistory) Remove(d MoveDirection) {
	entry := dh.directions[d]
	if entry.prev != nil {
		entry.prev.next = entry.next
	}
	if entry.next != nil {
		entry.next.prev = entry.prev
	}
	if entry == dh.tail {
		dh.tail = entry.prev
	}
	entry.prev = nil
	entry.next = nil
}

func (dh *DirectionsHistory) LatestDirection() (d MoveDirection) {
	if dh.tail != nil {
		return dh.tail.dir
	}
	return None
}

func NewDirectionsHistory() (dh *DirectionsHistory) {
	// Ugh, West+1 because we're generating a sparse array indexed on the
	// int value of directions; West should be the last one enumerated.
	dh = &DirectionsHistory{
		tail:       nil,
		directions: make([]*DirectionsHistoryEntry, West+1),
	}
	dirs := []MoveDirection{North, East, South, West}
	for _, d := range dirs {
		dh.directions[d] = &DirectionsHistoryEntry{
			prev: nil,
			next: nil,
			dir:  d,
		}
	}
	return
}

type Player struct {
	*twodee.AnimatingEntity
	MaxHealth         int32
	Health            int32
	Speed             float32
	Velocity          twodee.Point
	DirectionsHistory *DirectionsHistory
	DesiredMove       MoveDirection
	Inventory         []*Item
	State             EntityState
	CanGetItem        bool
	CanMove           bool
	IsPumping         bool
	destroyableItems  map[ItemId]bool
	HasFinalItem      bool
}

type EntityState int32

const (
	_                    = iota
	Standing EntityState = 1 << iota
	Walking
	Left
	Right
	Up
	Down
	ClimbUp
	ClimbDown
)

const (
	Fudge                = 0.4
	PlayerBaseSpeed      = 0.2
	PlayerFastSpeed      = 0.3
	PlayerSuperFastSpeed = 0.4
	PlayerBaseHealth     = 1000
	PlayerWaterDamage    = 6
	PlayerHealthRegen    = 4
)

var PlayerAnimations = map[EntityState][]int{
	Standing | Up:    []int{24},
	Standing | Down:  []int{8},
	Standing | Left:  []int{16},
	Standing | Right: []int{16},
	Walking | Up:     []int{25, 26, 27, 28, 29, 30},
	Walking | Down:   []int{9, 10, 11, 12, 13, 14},
	Walking | Left:   []int{17, 18, 19, 20, 21, 22},
	Walking | Right:  []int{17, 18, 19, 20, 21, 22},
	ClimbUp | Down:   []int{32, 33, 34, 35, 36, 37, 38, 8},
	ClimbDown | Down: []int{48, 49, 50, 51, 52, 53, 54, 8},
}

func NewPlayer(x, y float32) (player *Player) {
	var (
		inv = make([]*Item, 0, NumberOfItemTypes)
	)
	player = &Player{
		AnimatingEntity: twodee.NewAnimatingEntity(
			x, y,
			32.0/PxPerUnit, 32.0/PxPerUnit,
			0,
			twodee.Step10Hz,
			[]int{8},
		),
		MaxHealth:         PlayerBaseHealth,
		Health:            PlayerBaseHealth,
		Speed:             PlayerBaseSpeed,
		Velocity:          twodee.Pt(0, 0),
		DirectionsHistory: NewDirectionsHistory(),
		DesiredMove:       None,
		Inventory:         inv,
		CanGetItem:        true,
		CanMove:           true,
		IsPumping:         false,
		HasFinalItem:      false,
		destroyableItems:  make(map[ItemId]bool),
	}
	return
}

func (p *Player) RemState(state EntityState) {
	p.SetState(p.State & ^state)
}

func (p *Player) AddState(state EntityState) {
	p.SetState(p.State | state)
}

func (p *Player) SwapState(rem, add EntityState) {
	p.SetState(p.State & ^rem | add)
}

func (p *Player) SetState(state EntityState) {
	if state != p.State {
		p.State = state
		if frames, ok := PlayerAnimations[p.State]; ok {
			p.SetFrames(frames)
		}
	}
}

func (p *Player) FlippedX() bool {
	return p.State&Left > 0
}

// Updates the Player's desired movement direction as well as the affiliated data
// structures. If `invert`, then the movement key has been released and we should
// remove it from the affiliated data structures and perhaps pick a new movement
// direction from the tail of OrderedDirections.
func (p *Player) UpdateDesiredMove(d MoveDirection, invert bool) {
	if invert {
		p.DirectionsHistory.Remove(d)
		p.DesiredMove = p.DirectionsHistory.LatestDirection()
		return
	}
	// If the player is already moving in this direction, do nothing.
	if p.DesiredMove == d {
		return
	}
	p.DirectionsHistory.Add(d)
	p.DesiredMove = p.DirectionsHistory.LatestDirection()
}

func (p *Player) AttemptMove(l *Level) {
	if !p.CanMove {
		return
	}
	var (
		a, b, trunc twodee.Point
		bounds      = p.Bounds()
		pos         = p.Pos()
	)
	switch p.DesiredMove {
	case None:
		p.SwapState(Walking, Standing)
		return
	case North:
		a = twodee.Pt(bounds.Min.X+Fudge, bounds.Max.Y+p.Speed)
		b = twodee.Pt(bounds.Max.X-Fudge, bounds.Max.Y+p.Speed)
		pos.Y += p.Speed
		trunc = l.GridAlignedY(l.Active, pos)
		p.SetState(Walking | Up)
	case South:
		a = twodee.Pt(bounds.Min.X+Fudge, bounds.Min.Y-p.Speed)
		b = twodee.Pt(bounds.Max.X-Fudge, bounds.Min.Y-p.Speed)
		pos.Y -= p.Speed
		trunc = l.GridAlignedY(l.Active, pos)
		p.SetState(Walking | Down)
	case East:
		a = twodee.Pt(bounds.Max.X+p.Speed, bounds.Min.Y+Fudge)
		b = twodee.Pt(bounds.Max.X+p.Speed, bounds.Max.Y-Fudge)
		pos.X += p.Speed
		trunc = l.GridAlignedX(l.Active, pos)
		p.SetState(Walking | Right)
	case West:
		a = twodee.Pt(bounds.Min.X-p.Speed, bounds.Min.Y+Fudge)
		b = twodee.Pt(bounds.Min.X-p.Speed, bounds.Max.Y-Fudge)
		pos.X -= p.Speed
		trunc = l.GridAlignedX(l.Active, pos)
		p.SetState(Walking | Left)
	}
	if l.FrontierCollides(l.Active, a, b) {
		p.MoveTo(trunc)
	} else {
		p.MoveTo(pos)
	}
}

func (p *Player) AddToInventory(item *Item) {
	p.Inventory = append(p.Inventory, item)
	switch item.Id {
	case Item1:
		p.MaxHealth += 100
		p.Health += 100
	case Item2:
		p.MaxHealth += 100
		p.Health += 100
	case Item3:
		p.MaxHealth += PlayerBaseHealth
		p.Health += PlayerBaseHealth
	case Item4:
		if p.Speed < PlayerFastSpeed {
			p.Speed = PlayerFastSpeed
		}
	case ItemFinal:
		if p.Speed < PlayerSuperFastSpeed {
			p.Speed = PlayerSuperFastSpeed
		}
		p.HasFinalItem = true
	case ItemPickaxe:
		p.destroyableItems[ItemRock] = true
	}
}

func (p *Player) CanDestroy(item *Item) bool {
	return p.destroyableItems[item.Id]
}

func (p *Player) Update(elapsed time.Duration) {
	p.AnimatingEntity.Update(elapsed)
	if p.Health < p.MaxHealth {
		p.Health += PlayerHealthRegen
		if p.Health > p.MaxHealth {
			p.Health = p.MaxHealth
		}
	}
}

func (p *Player) Damage(damage int32) {
	p.Health -= damage
	if p.Health < 0 {
		p.Health = 0
	}
}

func (p *Player) HealthPercent() float32 {
	return float32(p.Health) / float32(p.MaxHealth)
}
<commit_msg>Have the player keep track of the last item used.<commit_after>package main

import (
	"time"

	"../libs/twodee"
)

type DirectionsHistoryEntry struct {
	prev, next *DirectionsHistoryEntry
	dir        MoveDirection
}

type DirectionsHistory struct {
	tail       *DirectionsHistoryEntry
	directions []*DirectionsHistoryEntry
}

// Adds a MoveDirection to the history if it's not already present.
func (dh *DirectionsHistory) Add(d MoveDirection) {
	entry := dh.directions[d]
	if entry.prev == nil && entry.next == nil && entry != dh.tail {
		if dh.tail != nil {
			dh.tail.next = entry
			entry.prev = dh.tail
		}
		dh.tail = entry
	}
}

// Removes a particular MoveDirection from the history chain; sets its prev and next fields to nil. Resets dh's tail if necessary.
func (dh *DirectionsHistory) Remove(d MoveDirection) {
	entry := dh.directions[d]
	if entry.prev != nil {
		entry.prev.next = entry.next
	}
	if entry.next != nil {
		entry.next.prev = entry.prev
	}
	if entry == dh.tail {
		dh.tail = entry.prev
	}
	entry.prev = nil
	entry.next = nil
}

func (dh *DirectionsHistory) LatestDirection() (d MoveDirection) {
	if dh.tail != nil {
		return dh.tail.dir
	}
	return None
}

func NewDirectionsHistory() (dh *DirectionsHistory) {
	// Ugh, West+1 because we're generating a sparse array indexed on the
	// int value of directions; West should be the last one enumerated.
	dh = &DirectionsHistory{
		tail:       nil,
		directions: make([]*DirectionsHistoryEntry, West+1),
	}
	dirs := []MoveDirection{North, East, South, West}
	for _, d := range dirs {
		dh.directions[d] = &DirectionsHistoryEntry{
			prev: nil,
			next: nil,
			dir:  d,
		}
	}
	return
}

type Player struct {
	*twodee.AnimatingEntity
	MaxHealth         int32
	Health            int32
	Speed             float32
	Velocity          twodee.Point
	DirectionsHistory *DirectionsHistory
	DesiredMove       MoveDirection
	Inventory         []*Item
	State             EntityState
	CanGetItem        bool
	CanMove           bool
	IsPumping         bool
	destroyableItems  map[ItemId]bool
	HasFinalItem      bool
	LastUsed          *Item
}

type EntityState int32

const (
	_                    = iota
	Standing EntityState = 1 << iota
	Walking
	Left
	Right
	Up
	Down
	ClimbUp
	ClimbDown
)

const (
	Fudge                = 0.4
	PlayerBaseSpeed      = 0.2
	PlayerFastSpeed      = 0.3
	PlayerSuperFastSpeed = 0.4
	PlayerBaseHealth     = 1000
	PlayerWaterDamage    = 6
	PlayerHealthRegen    = 4
)

var PlayerAnimations = map[EntityState][]int{
	Standing | Up:    []int{24},
	Standing | Down:  []int{8},
	Standing | Left:  []int{16},
	Standing | Right: []int{16},
	Walking | Up:     []int{25, 26, 27, 28, 29, 30},
	Walking | Down:   []int{9, 10, 11, 12, 13, 14},
	Walking | Left:   []int{17, 18, 19, 20, 21, 22},
	Walking | Right:  []int{17, 18, 19, 20, 21, 22},
	ClimbUp | Down:   []int{32, 33, 34, 35, 36, 37, 38, 8},
	ClimbDown | Down: []int{48, 49, 50, 51, 52, 53, 54, 8},
}

func NewPlayer(x, y float32) (player *Player) {
	var (
		inv = make([]*Item, 0, NumberOfItemTypes)
	)
	player = &Player{
		AnimatingEntity: twodee.NewAnimatingEntity(
			x, y,
			32.0/PxPerUnit, 32.0/PxPerUnit,
			0,
			twodee.Step10Hz,
			[]int{8},
		),
		MaxHealth:         PlayerBaseHealth,
		Health:            PlayerBaseHealth,
		Speed:             PlayerBaseSpeed,
		Velocity:          twodee.Pt(0, 0),
		DirectionsHistory: NewDirectionsHistory(),
		DesiredMove:       None,
		Inventory:         inv,
		CanGetItem:        true,
		CanMove:           true,
		IsPumping:         false,
		HasFinalItem:      false,
		destroyableItems:  make(map[ItemId]bool),
		LastUsed:          nil,
	}
	return
}

func (p *Player) RemState(state EntityState) {
	p.SetState(p.State & ^state)
}

func (p *Player) AddState(state EntityState) {
	p.SetState(p.State | state)
}

func (p *Player) SwapState(rem, add EntityState) {
	p.SetState(p.State & ^rem | add)
}

func (p *Player) SetState(state EntityState) {
	if state != p.State {
		p.State = state
		if frames, ok := PlayerAnimations[p.State]; ok {
			p.SetFrames(frames)
		}
	}
}

func (p *Player) FlippedX() bool {
	return p.State&Left > 0
}

// Updates the Player's desired movement direction as well as the affiliated data
// structures. If `invert`, then the movement key has been released and we should
// remove it from the affiliated data structures and perhaps pick a new movement
// direction from the tail of OrderedDirections.
func (p *Player) UpdateDesiredMove(d MoveDirection, invert bool) {
	if invert {
		p.DirectionsHistory.Remove(d)
		p.DesiredMove = p.DirectionsHistory.LatestDirection()
		return
	}
	// If the player is already moving in this direction, do nothing.
	if p.DesiredMove == d {
		return
	}
	p.DirectionsHistory.Add(d)
	p.DesiredMove = p.DirectionsHistory.LatestDirection()
}

func (p *Player) AttemptMove(l *Level) {
	if !p.CanMove {
		return
	}
	var (
		a, b, trunc twodee.Point
		bounds      = p.Bounds()
		pos         = p.Pos()
	)
	switch p.DesiredMove {
	case None:
		p.SwapState(Walking, Standing)
		return
	case North:
		a = twodee.Pt(bounds.Min.X+Fudge, bounds.Max.Y+p.Speed)
		b = twodee.Pt(bounds.Max.X-Fudge, bounds.Max.Y+p.Speed)
		pos.Y += p.Speed
		trunc = l.GridAlignedY(l.Active, pos)
		p.SetState(Walking | Up)
	case South:
		a = twodee.Pt(bounds.Min.X+Fudge, bounds.Min.Y-p.Speed)
		b = twodee.Pt(bounds.Max.X-Fudge, bounds.Min.Y-p.Speed)
		pos.Y -= p.Speed
		trunc = l.GridAlignedY(l.Active, pos)
		p.SetState(Walking | Down)
	case East:
		a = twodee.Pt(bounds.Max.X+p.Speed, bounds.Min.Y+Fudge)
		b = twodee.Pt(bounds.Max.X+p.Speed, bounds.Max.Y-Fudge)
		pos.X += p.Speed
		trunc = l.GridAlignedX(l.Active, pos)
		p.SetState(Walking | Right)
	case West:
		a = twodee.Pt(bounds.Min.X-p.Speed, bounds.Min.Y+Fudge)
		b = twodee.Pt(bounds.Min.X-p.Speed, bounds.Max.Y-Fudge)
		pos.X -= p.Speed
		trunc = l.GridAlignedX(l.Active, pos)
		p.SetState(Walking | Left)
	}
	if l.FrontierCollides(l.Active, a, b) {
		p.MoveTo(trunc)
	} else {
		p.MoveTo(pos)
	}
}

func (p *Player) AddToInventory(item *Item) {
	p.Inventory = append(p.Inventory, item)
	switch item.Id {
	case Item1:
		p.MaxHealth += 100
		p.Health += 100
	case Item2:
		p.MaxHealth += 100
		p.Health += 100
	case Item3:
		p.MaxHealth += PlayerBaseHealth
		p.Health += PlayerBaseHealth
	case Item4:
		if p.Speed < PlayerFastSpeed {
			p.Speed = PlayerFastSpeed
		}
	case ItemFinal:
		if p.Speed < PlayerSuperFastSpeed {
			p.Speed = PlayerSuperFastSpeed
		}
		p.HasFinalItem = true
	case ItemPickaxe:
		p.destroyableItems[ItemRock] = true
	}
}

func (p *Player) CanDestroy(item *Item) bool {
	return p.destroyableItems[item.Id]
}

func (p *Player) Update(elapsed time.Duration) {
	p.AnimatingEntity.Update(elapsed)
	if p.Health < p.MaxHealth {
		p.Health += PlayerHealthRegen
		if p.Health > p.MaxHealth {
			p.Health = p.MaxHealth
		}
	}
}

func (p *Player) Damage(damage int32) {
	p.Health -= damage
	if p.Health < 0 {
		p.Health = 0
	}
}

func (p *Player) HealthPercent() float32 {
	return float32(p.Health) / float32(p.MaxHealth)
}
<|endoftext|>


<commit_before>package integration

import (
	"fmt"

	. "code.cloudfoundry.org/cli/integration/helpers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
)

var _ = Describe("run-task command", func() {
	var (
		orgName   string
		spaceName string
		appName   string
	)

	BeforeEach(func() {
		Skip("until bosh-lites are running CAPI V2.64")
		orgName = PrefixedRandomName("ORG")
		spaceName = PrefixedRandomName("SPACE")
		appName = PrefixedRandomName("APP")

		setupCF(orgName, spaceName)
	})

	AfterEach(func() {
		setAPI()
		loginCF()
		Eventually(CF("delete-org", "-f", orgName), CFLongTimeout).Should(Exit(0))
	})

	It("should display the command level help", func() {
		session := CF("run-task", "-h")
		Eventually(session).Should(Exit(0))
		Expect(session.Out).To(Say(`NAME:
   run-task - Run a one-off task on an app

USAGE:
   cf run-task APP_NAME COMMAND

EXAMPLES:
   cf run-task my-app "bundle exec rake db:migrate"

ALIAS:
   rt

SEE ALSO:
   tasks, terminate-task`))
	})

	Context("when the environment is not setup correctly", func() {
		Context("when no API endpoint is set", func() {
			BeforeEach(func() {
				unsetAPI()
			})

			It("fails with no API endpoint set message", func() {
				session := CF("run-task", "app-name", "some command")
				Eventually(session).Should(Exit(1))
				Expect(session.Out).To(Say("FAILED"))
				Expect(session.Err).To(Say("No API endpoint set. Use 'cf login' or 'cf api' to target an endpoint."))
			})
		})

		Context("when not logged in", func() {
			BeforeEach(func() {
				logoutCF()
			})

			It("fails with not logged in message", func() {
				session := CF("run-task", "app-name", "some command")
				Eventually(session).Should(Exit(1))
				Expect(session.Out).To(Say("FAILED"))
				Expect(session.Err).To(Say("Not logged in. Use 'cf login' to log in."))
			})
		})

		Context("when there no org set", func() {
			BeforeEach(func() {
				logoutCF()
				loginCF()
			})

			It("fails with no targeted org error message", func() {
				session := CF("run-task", "app-name", "some command")
				Eventually(session).Should(Exit(1))
				Expect(session.Out).To(Say("FAILED"))
				Expect(session.Err).To(Say("No org targeted, use 'cf target -o ORG' to target an org."))
			})
		})

		Context("when there no space set", func() {
			BeforeEach(func() {
				// create a another space, because if the org has only one space it
				// will be automatically targetted
				createSpace(PrefixedRandomName("SPACE"))
				logoutCF()
				loginCF()
				targetOrg(orgName)
			})

			It("fails with no space targeted error message", func() {
				session := CF("run-task", "app-name", "some command")
				Eventually(session).Should(Exit(1))
				Expect(session.Out).To(Say("FAILED"))
				Expect(session.Err).To(Say("No space targeted, use 'cf target -s SPACE' to target a space"))
			})
		})
	})

	Context("when the environment is setup correctly", func() {
		Context("when the application exists", func() {
			BeforeEach(func() {
				WithSimpleApp(func(appDir string) {
					Eventually(CF("push", appName, "-p", appDir, "-b", "staticfile_buildpack"), CFLongTimeout).Should(Exit(0))
				})
			})

			It("creates a new task", func() {
				session := CF("run-task", appName, "echo hi")
				Eventually(session).Should(Exit(0))
				userName, _ := getCredentials()
				Expect(session.Out).To(Say(fmt.Sprintf("Creating task for app %s in org %s / space %s as %s...", appName, orgName, spaceName, userName)))
				Expect(session.Out).To(Say(`OK

Task 1 has been submitted successfully for execution.`,
				))
			})
		})

		Context("when the application is not staged", func() {
			BeforeEach(func() {
				WithSimpleApp(func(appDir string) {
					Eventually(CF("push", appName, "--no-start", "-p", appDir, "-b", "staticfile_buildpack"), CFLongTimeout).Should(Exit(0))
				})
			})

			It("fails and outputs task must have a droplet message", func() {
				session := CF("run-task", appName, "echo hi")
				Eventually(session).Should(Exit(1))
				Expect(session.Out).To(Say("FAILED"))
				Expect(session.Err).To(Say(`Unexpected Response
Response Code: 422
Code: 10008, Title: CF-UnprocessableEntity, Detail: The request is semantically invalid: Task must have a droplet. Specify droplet or assign current droplet to app`))
			})
		})

		Context("when the application is staged but stopped", func() {
			BeforeEach(func() {
				WithSimpleApp(func(appDir string) {
					Eventually(CF("push", appName, "-p", appDir, "-b", "staticfile_buildpack"), CFLongTimeout).Should(Exit(0))
				})
				session := CF("stop", appName)
				Eventually(session).Should(Exit(0))
			})

			It("creates a new task", func() {
				session := CF("run-task", appName, "echo hi")
				Eventually(session).Should(Exit(0))
				userName, _ := getCredentials()
				Expect(session.Out).To(Say(fmt.Sprintf("Creating task for app %s in org %s / space %s as %s...", appName, orgName, spaceName, userName)))
				Expect(session.Out).To(Say(`OK

Task 1 has been submitted successfully for execution.`,
				))
			})
		})

		Context("when the application does not exist", func() {
			It("fails and outputs an app not found message", func() {
				session := CF("run-task", appName, "echo hi")
				Eventually(session).Should(Exit(1))
				Expect(session.Out).To(Say("FAILED"))
				Expect(session.Err).To(Say(fmt.Sprintf("App %s not found", appName)))
			})
		})
	})
})
<commit_msg>remove skip for run-task integration tests<commit_after>package integration

import (
	"fmt"

	. "code.cloudfoundry.org/cli/integration/helpers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
)

var _ = Describe("run-task command", func() {
	var (
		orgName   string
		spaceName string
		appName   string
	)

	BeforeEach(func() {
		orgName = PrefixedRandomName("ORG")
		spaceName = PrefixedRandomName("SPACE")
		appName = PrefixedRandomName("APP")

		setupCF(orgName, spaceName)
	})

	AfterEach(func() {
		setAPI()
		loginCF()
		Eventually(CF("delete-org", "-f", orgName), CFLongTimeout).Should(Exit(0))
	})

	It("should display the command level help", func() {
		session := CF("run-task", "-h")
		Eventually(session).Should(Exit(0))
		Expect(session.Out).To(Say(`NAME:
   run-task - Run a one-off task on an app

USAGE:
   cf run-task APP_NAME COMMAND

EXAMPLES:
   cf run-task my-app "bundle exec rake db:migrate"

ALIAS:
   rt

SEE ALSO:
   tasks, terminate-task`))
	})

	Context("when the environment is not setup correctly", func() {
		Context("when no API endpoint is set", func() {
			BeforeEach(func() {
				unsetAPI()
			})

			It("fails with no API endpoint set message", func() {
				session := CF("run-task", "app-name", "some command")
				Eventually(session).Should(Exit(1))
				Expect(session.Out).To(Say("FAILED"))
				Expect(session.Err).To(Say("No API endpoint set. Use 'cf login' or 'cf api' to target an endpoint."))
			})
		})

		Context("when not logged in", func() {
			BeforeEach(func() {
				logoutCF()
			})

			It("fails with not logged in message", func() {
				session := CF("run-task", "app-name", "some command")
				Eventually(session).Should(Exit(1))
				Expect(session.Out).To(Say("FAILED"))
				Expect(session.Err).To(Say("Not logged in. Use 'cf login' to log in."))
			})
		})

		Context("when there no org set", func() {
			BeforeEach(func() {
				logoutCF()
				loginCF()
			})

			It("fails with no targeted org error message", func() {
				session := CF("run-task", "app-name", "some command")
				Eventually(session).Should(Exit(1))
				Expect(session.Out).To(Say("FAILED"))
				Expect(session.Err).To(Say("No org targeted, use 'cf target -o ORG' to target an org."))
			})
		})

		Context("when there no space set", func() {
			BeforeEach(func() {
				// create a another space, because if the org has only one space it
				// will be automatically targetted
				createSpace(PrefixedRandomName("SPACE"))
				logoutCF()
				loginCF()
				targetOrg(orgName)
			})

			It("fails with no space targeted error message", func() {
				session := CF("run-task", "app-name", "some command")
				Eventually(session).Should(Exit(1))
				Expect(session.Out).To(Say("FAILED"))
				Expect(session.Err).To(Say("No space targeted, use 'cf target -s SPACE' to target a space"))
			})
		})
	})

	Context("when the environment is setup correctly", func() {
		Context("when the application exists", func() {
			BeforeEach(func() {
				WithSimpleApp(func(appDir string) {
					Eventually(CF("push", appName, "-p", appDir, "-b", "staticfile_buildpack"), CFLongTimeout).Should(Exit(0))
				})
			})

			It("creates a new task", func() {
				session := CF("run-task", appName, "echo hi")
				Eventually(session).Should(Exit(0))
				userName, _ := getCredentials()
				Expect(session.Out).To(Say(fmt.Sprintf("Creating task for app %s in org %s / space %s as %s...", appName, orgName, spaceName, userName)))
				Expect(session.Out).To(Say(`OK

Task 1 has been submitted successfully for execution.`,
				))
			})
		})

		Context("when the application is not staged", func() {
			BeforeEach(func() {
				WithSimpleApp(func(appDir string) {
					Eventually(CF("push", appName, "--no-start", "-p", appDir, "-b", "staticfile_buildpack"), CFLongTimeout).Should(Exit(0))
				})
			})

			It("fails and outputs task must have a droplet message", func() {
				session := CF("run-task", appName, "echo hi")
				Eventually(session).Should(Exit(1))
				Expect(session.Out).To(Say("FAILED"))
				Expect(session.Err).To(Say(`Unexpected Response
Response Code: 422
Code: 10008, Title: CF-UnprocessableEntity, Detail: The request is semantically invalid: Task must have a droplet. Specify droplet or assign current droplet to app`))
			})
		})

		Context("when the application is staged but stopped", func() {
			BeforeEach(func() {
				WithSimpleApp(func(appDir string) {
					Eventually(CF("push", appName, "-p", appDir, "-b", "staticfile_buildpack"), CFLongTimeout).Should(Exit(0))
				})
				session := CF("stop", appName)
				Eventually(session).Should(Exit(0))
			})

			It("creates a new task", func() {
				session := CF("run-task", appName, "echo hi")
				Eventually(session).Should(Exit(0))
				userName, _ := getCredentials()
				Expect(session.Out).To(Say(fmt.Sprintf("Creating task for app %s in org %s / space %s as %s...", appName, orgName, spaceName, userName)))
				Expect(session.Out).To(Say(`OK

Task 1 has been submitted successfully for execution.`,
				))
			})
		})

		Context("when the application does not exist", func() {
			It("fails and outputs an app not found message", func() {
				session := CF("run-task", appName, "echo hi")
				Eventually(session).Should(Exit(1))
				Expect(session.Out).To(Say("FAILED"))
				Expect(session.Err).To(Say(fmt.Sprintf("App %s not found", appName)))
			})
		})
	})
})
<|endoftext|>


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

package rpcreplay

import (
	"bytes"
	"context"
	"io"
	"reflect"
	"testing"

	"github.com/golang/protobuf/proto"

	ipb "cloud.google.com/go/internal/rpcreplay/proto/intstore"
	rpb "cloud.google.com/go/internal/rpcreplay/proto/rpcreplay"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

func TestRecordIO(t *testing.T) {
	buf := &bytes.Buffer{}
	want := []byte{1, 2, 3}
	if err := writeRecord(buf, want); err != nil {
		t.Fatal(err)
	}
	got, err := readRecord(buf)
	if err != nil {
		t.Fatal(err)
	}
	if !bytes.Equal(got, want) {
		t.Errorf("got %v, want %v", got, want)
	}
}

func TestHeaderIO(t *testing.T) {
	buf := &bytes.Buffer{}
	want := []byte{1, 2, 3}
	if err := writeHeader(buf, want); err != nil {
		t.Fatal(err)
	}
	got, err := readHeader(buf)
	if err != nil {
		t.Fatal(err)
	}
	if !reflect.DeepEqual(got, want) {
		t.Errorf("got %v, want %v", got, want)
	}

	// readHeader errors
	for _, contents := range []string{"", "badmagic", "gRPCReplay"} {
		if _, err := readHeader(bytes.NewBufferString(contents)); err == nil {
			t.Errorf("%q: got nil, want error", contents)
		}
	}
}

func TestEntryIO(t *testing.T) {
	for i, want := range []*entry{
		{
			kind:     rpb.Entry_REQUEST,
			method:   "method",
			msg:      message{msg: &rpb.Entry{}},
			refIndex: 7,
		},
		{
			kind:     rpb.Entry_RESPONSE,
			method:   "method",
			msg:      message{err: status.Error(codes.NotFound, "not found")},
			refIndex: 8,
		},
		{
			kind:     rpb.Entry_RECV,
			method:   "method",
			msg:      message{err: io.EOF},
			refIndex: 3,
		},
	} {
		buf := &bytes.Buffer{}
		if err := writeEntry(buf, want); err != nil {
			t.Fatal(err)
		}
		got, err := readEntry(buf)
		if err != nil {
			t.Fatal(err)
		}
		if !got.equal(want) {
			t.Errorf("#%d: got %v, want %v", i, got, want)
		}
	}
}

var initialState = []byte{1, 2, 3}

func TestRecord(t *testing.T) {
	srv := newIntStoreServer()
	defer srv.stop()
	buf := record(t, srv)

	gotIstate, err := readHeader(buf)
	if err != nil {
		t.Fatal(err)
	}
	if !reflect.DeepEqual(gotIstate, initialState) {
		t.Fatalf("got %v, want %v", gotIstate, initialState)
	}
	item := &ipb.Item{Name: "a", Value: 1}
	wantEntries := []*entry{
		// Set
		{
			kind:   rpb.Entry_REQUEST,
			method: "/intstore.IntStore/Set",
			msg:    message{msg: item},
		},
		{
			kind:     rpb.Entry_RESPONSE,
			msg:      message{msg: &ipb.SetResponse{PrevValue: 0}},
			refIndex: 1,
		},
		// Get
		{
			kind:   rpb.Entry_REQUEST,
			method: "/intstore.IntStore/Get",
			msg:    message{msg: &ipb.GetRequest{Name: "a"}},
		},
		{
			kind:     rpb.Entry_RESPONSE,
			msg:      message{msg: item},
			refIndex: 3,
		},
		{
			kind:   rpb.Entry_REQUEST,
			method: "/intstore.IntStore/Get",
			msg:    message{msg: &ipb.GetRequest{Name: "x"}},
		},
		{
			kind:     rpb.Entry_RESPONSE,
			msg:      message{err: status.Error(codes.NotFound, `"x"`)},
			refIndex: 5,
		},
	}
	for i, w := range wantEntries {
		g, err := readEntry(buf)
		if err != nil {
			t.Fatal(err)
		}
		if !g.equal(w) {
			t.Errorf("#%d:\ngot  %+v\nwant %+v", i+1, g, w)
		}
	}
	g, err := readEntry(buf)
	if err != nil {
		t.Fatal(err)
	}
	if g != nil {
		t.Errorf("\ngot  %+v\nwant nil", g)
	}
}

func record(t *testing.T, srv *intStoreServer) *bytes.Buffer {
	buf := &bytes.Buffer{}
	rec, err := NewRecorderWriter(buf, initialState)
	if err != nil {
		t.Fatal(err)
	}
	testService(t, srv.Addr, rec.DialOptions())
	if err := rec.Close(); err != nil {
		t.Fatal(err)
	}
	return buf
}

func testService(t *testing.T, addr string, opts []grpc.DialOption) {
	conn, err := grpc.Dial(addr,
		append([]grpc.DialOption{grpc.WithInsecure()}, opts...)...)
	if err != nil {
		t.Fatal(err)
	}
	defer conn.Close()
	client := ipb.NewIntStoreClient(conn)
	ctx := context.Background()
	item := &ipb.Item{Name: "a", Value: 1}
	res, err := client.Set(ctx, item)
	if err != nil {
		t.Fatal(err)
	}
	if res.PrevValue != 0 {
		t.Errorf("got %d, want 0", res.PrevValue)
	}
	got, err := client.Get(ctx, &ipb.GetRequest{Name: "a"})
	if err != nil {
		t.Fatal(err)
	}
	if !proto.Equal(got, item) {
		t.Errorf("got %v, want %v", got, item)
	}
	_, err = client.Get(ctx, &ipb.GetRequest{Name: "x"})
	if err == nil {
		t.Fatal("got nil, want error")
	}
	if _, ok := status.FromError(err); !ok {
		t.Errorf("got error type %T, want a grpc/status.Status", err)
	}
}
<commit_msg>rpcreplay: fix context import<commit_after>// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package rpcreplay

import (
	"bytes"
	"io"
	"reflect"
	"testing"

	ipb "cloud.google.com/go/internal/rpcreplay/proto/intstore"
	rpb "cloud.google.com/go/internal/rpcreplay/proto/rpcreplay"
	"github.com/golang/protobuf/proto"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

func TestRecordIO(t *testing.T) {
	buf := &bytes.Buffer{}
	want := []byte{1, 2, 3}
	if err := writeRecord(buf, want); err != nil {
		t.Fatal(err)
	}
	got, err := readRecord(buf)
	if err != nil {
		t.Fatal(err)
	}
	if !bytes.Equal(got, want) {
		t.Errorf("got %v, want %v", got, want)
	}
}

func TestHeaderIO(t *testing.T) {
	buf := &bytes.Buffer{}
	want := []byte{1, 2, 3}
	if err := writeHeader(buf, want); err != nil {
		t.Fatal(err)
	}
	got, err := readHeader(buf)
	if err != nil {
		t.Fatal(err)
	}
	if !reflect.DeepEqual(got, want) {
		t.Errorf("got %v, want %v", got, want)
	}

	// readHeader errors
	for _, contents := range []string{"", "badmagic", "gRPCReplay"} {
		if _, err := readHeader(bytes.NewBufferString(contents)); err == nil {
			t.Errorf("%q: got nil, want error", contents)
		}
	}
}

func TestEntryIO(t *testing.T) {
	for i, want := range []*entry{
		{
			kind:     rpb.Entry_REQUEST,
			method:   "method",
			msg:      message{msg: &rpb.Entry{}},
			refIndex: 7,
		},
		{
			kind:     rpb.Entry_RESPONSE,
			method:   "method",
			msg:      message{err: status.Error(codes.NotFound, "not found")},
			refIndex: 8,
		},
		{
			kind:     rpb.Entry_RECV,
			method:   "method",
			msg:      message{err: io.EOF},
			refIndex: 3,
		},
	} {
		buf := &bytes.Buffer{}
		if err := writeEntry(buf, want); err != nil {
			t.Fatal(err)
		}
		got, err := readEntry(buf)
		if err != nil {
			t.Fatal(err)
		}
		if !got.equal(want) {
			t.Errorf("#%d: got %v, want %v", i, got, want)
		}
	}
}

var initialState = []byte{1, 2, 3}

func TestRecord(t *testing.T) {
	srv := newIntStoreServer()
	defer srv.stop()
	buf := record(t, srv)

	gotIstate, err := readHeader(buf)
	if err != nil {
		t.Fatal(err)
	}
	if !reflect.DeepEqual(gotIstate, initialState) {
		t.Fatalf("got %v, want %v", gotIstate, initialState)
	}
	item := &ipb.Item{Name: "a", Value: 1}
	wantEntries := []*entry{
		// Set
		{
			kind:   rpb.Entry_REQUEST,
			method: "/intstore.IntStore/Set",
			msg:    message{msg: item},
		},
		{
			kind:     rpb.Entry_RESPONSE,
			msg:      message{msg: &ipb.SetResponse{PrevValue: 0}},
			refIndex: 1,
		},
		// Get
		{
			kind:   rpb.Entry_REQUEST,
			method: "/intstore.IntStore/Get",
			msg:    message{msg: &ipb.GetRequest{Name: "a"}},
		},
		{
			kind:     rpb.Entry_RESPONSE,
			msg:      message{msg: item},
			refIndex: 3,
		},
		{
			kind:   rpb.Entry_REQUEST,
			method: "/intstore.IntStore/Get",
			msg:    message{msg: &ipb.GetRequest{Name: "x"}},
		},
		{
			kind:     rpb.Entry_RESPONSE,
			msg:      message{err: status.Error(codes.NotFound, `"x"`)},
			refIndex: 5,
		},
	}
	for i, w := range wantEntries {
		g, err := readEntry(buf)
		if err != nil {
			t.Fatal(err)
		}
		if !g.equal(w) {
			t.Errorf("#%d:\ngot  %+v\nwant %+v", i+1, g, w)
		}
	}
	g, err := readEntry(buf)
	if err != nil {
		t.Fatal(err)
	}
	if g != nil {
		t.Errorf("\ngot  %+v\nwant nil", g)
	}
}

func record(t *testing.T, srv *intStoreServer) *bytes.Buffer {
	buf := &bytes.Buffer{}
	rec, err := NewRecorderWriter(buf, initialState)
	if err != nil {
		t.Fatal(err)
	}
	testService(t, srv.Addr, rec.DialOptions())
	if err := rec.Close(); err != nil {
		t.Fatal(err)
	}
	return buf
}

func testService(t *testing.T, addr string, opts []grpc.DialOption) {
	conn, err := grpc.Dial(addr,
		append([]grpc.DialOption{grpc.WithInsecure()}, opts...)...)
	if err != nil {
		t.Fatal(err)
	}
	defer conn.Close()
	client := ipb.NewIntStoreClient(conn)
	ctx := context.Background()
	item := &ipb.Item{Name: "a", Value: 1}
	res, err := client.Set(ctx, item)
	if err != nil {
		t.Fatal(err)
	}
	if res.PrevValue != 0 {
		t.Errorf("got %d, want 0", res.PrevValue)
	}
	got, err := client.Get(ctx, &ipb.GetRequest{Name: "a"})
	if err != nil {
		t.Fatal(err)
	}
	if !proto.Equal(got, item) {
		t.Errorf("got %v, want %v", got, item)
	}
	_, err = client.Get(ctx, &ipb.GetRequest{Name: "x"})
	if err == nil {
		t.Fatal("got nil, want error")
	}
	if _, ok := status.FromError(err); !ok {
		t.Errorf("got error type %T, want a grpc/status.Status", err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"net/rpc"
	"net/rpc/jsonrpc"

	"honnef.co/go/js/dom"

	"github.com/MJKWoolnough/gopherjs/xdom"
	"github.com/MJKWoolnough/gopherjs/xjs"
	"github.com/MJKWoolnough/minewebgen/internal/data"
	"github.com/gopherjs/gopherjs/js"
	"github.com/gopherjs/websocket"
)

type jRPC struct {
	rpc *rpc.Client
}

func rpcInit() error {
	conn, err := websocket.Dial("ws://" + js.Global.Get("location").Get("host").String() + "/rpc")
	if err != nil {
		return err
	}
	conn.WebSocket.Call("addEventListener", "close", func(*js.Object) {
		xjs.RemoveChildren(dom.GetWindow().Document().(dom.HTMLDocument).Body()).AppendChild(xjs.SetInnerText(xdom.H1(), "Connection Lost"))
	}, false)
	dom.GetWindow().AddEventListener("beforeunload", false, func(dom.Event) {
		switch conn.ReadyState {
		case websocket.Connecting, websocket.Open:
			conn.Close()
		}
	})
	RPC = jRPC{jsonrpc.NewClient(conn)}
	return nil
}

var (
	RPC jRPC
	es  = &struct{}{}
)

func (j jRPC) Settings() (data.ServerSettings, error) {
	var s data.ServerSettings
	err := j.rpc.Call("RPC.ServerSettings", nil, &s)
	return s, err
}

func (j jRPC) SetSettings(settings data.ServerSettings) error {
	return j.rpc.Call("RPC.SetSettings", settings, es)
}

func (j jRPC) ServerName() (string, error) {
	var name string
	err := j.rpc.Call("RPC.Name", nil, &name)
	return name, err
}

func (j jRPC) ServerList() ([]data.Server, error) {
	var list []data.Server
	err := j.rpc.Call("RPC.ServerList", nil, &list)
	return list, err
}

func (j jRPC) MapList() ([]data.Map, error) {
	var list []data.Map
	err := j.rpc.Call("RPC.MapList", nil, &list)
	return list, err
}

func (j jRPC) Server(id int) (data.Server, error) {
	var s data.Server
	err := j.rpc.Call("RPC.Server", id, &s)
	return s, err
}

func (j jRPC) Map(id int) (data.Map, error) {
	var m data.Map
	err := j.rpc.Call("RPC.Map", id, &m)
	return m, err
}

func (j jRPC) SetServer(s data.Server) error {
	return j.rpc.Call("RPC.SetServer", s, es)
}

func (j jRPC) SetMap(m data.Map) error {
	return j.rpc.Call("RPC.SetMap", m, es)
}

func (j jRPC) SetServerMap(serverID, mapID int) error {
	return j.rpc.Call("RPC.SetServerMap", [2]int{serverID, mapID}, es)
}

func (j jRPC) ServerProperties(id int) (map[string]string, error) {
	sp := make(map[string]string)
	err := j.rpc.Call("RPC.ServerProperties", id, &sp)
	return sp, err
}

func (j jRPC) SetServerProperties(id int, properties map[string]string) error {
	return j.rpc.Call("RPC.SetServerProperties", data.ServerProperties{id, properties}, es)
}

func (j jRPC) MapProperties(id int) (map[string]string, error) {
	mp := make(map[string]string)
	err := j.rpc.Call("RPC.MapProperties", id, &mp)
	return mp, err
}

func (j jRPC) SetMapProperties(id int, properties map[string]string) error {
	return j.rpc.Call("RPC.SetMapProperties", data.ServerProperties{id, properties}, es)
}

func (j jRPC) RemoveServer(id int) error {
	return j.rpc.Call("RPC.RemoveServer", id, es)
}

func (j jRPC) RemoveMap(id int) error {
	return j.rpc.Call("RPC.RemoveMap", id, es)
}

func (j jRPC) CreateDefaultMap(d data.DefaultMap) error {
	return j.rpc.Call("RPC.CreateDefaultMap", d, es)
}

func (j jRPC) CreateSuperflatMap(d data.SuperFlatMap) error {
	return j.rpc.Call("RPC.CreateSuperflatMap", d, es)
}

func (j jRPC) CreateCustomMap(d data.CustomMap) error {
	return j.rpc.Call("RPC.CreateCustomMap", d, es)
}
<commit_msg>Added Start/Stop Server to client-side rpc<commit_after>package main

import (
	"net/rpc"
	"net/rpc/jsonrpc"

	"honnef.co/go/js/dom"

	"github.com/MJKWoolnough/gopherjs/xdom"
	"github.com/MJKWoolnough/gopherjs/xjs"
	"github.com/MJKWoolnough/minewebgen/internal/data"
	"github.com/gopherjs/gopherjs/js"
	"github.com/gopherjs/websocket"
)

type jRPC struct {
	rpc *rpc.Client
}

func rpcInit() error {
	conn, err := websocket.Dial("ws://" + js.Global.Get("location").Get("host").String() + "/rpc")
	if err != nil {
		return err
	}
	conn.WebSocket.Call("addEventListener", "close", func(*js.Object) {
		xjs.RemoveChildren(dom.GetWindow().Document().(dom.HTMLDocument).Body()).AppendChild(xjs.SetInnerText(xdom.H1(), "Connection Lost"))
	}, false)
	dom.GetWindow().AddEventListener("beforeunload", false, func(dom.Event) {
		switch conn.ReadyState {
		case websocket.Connecting, websocket.Open:
			conn.Close()
		}
	})
	RPC = jRPC{jsonrpc.NewClient(conn)}
	return nil
}

var (
	RPC jRPC
	es  = &struct{}{}
)

func (j jRPC) Settings() (data.ServerSettings, error) {
	var s data.ServerSettings
	err := j.rpc.Call("RPC.ServerSettings", nil, &s)
	return s, err
}

func (j jRPC) SetSettings(settings data.ServerSettings) error {
	return j.rpc.Call("RPC.SetSettings", settings, es)
}

func (j jRPC) ServerName() (string, error) {
	var name string
	err := j.rpc.Call("RPC.Name", nil, &name)
	return name, err
}

func (j jRPC) ServerList() ([]data.Server, error) {
	var list []data.Server
	err := j.rpc.Call("RPC.ServerList", nil, &list)
	return list, err
}

func (j jRPC) MapList() ([]data.Map, error) {
	var list []data.Map
	err := j.rpc.Call("RPC.MapList", nil, &list)
	return list, err
}

func (j jRPC) Server(id int) (data.Server, error) {
	var s data.Server
	err := j.rpc.Call("RPC.Server", id, &s)
	return s, err
}

func (j jRPC) Map(id int) (data.Map, error) {
	var m data.Map
	err := j.rpc.Call("RPC.Map", id, &m)
	return m, err
}

func (j jRPC) SetServer(s data.Server) error {
	return j.rpc.Call("RPC.SetServer", s, es)
}

func (j jRPC) SetMap(m data.Map) error {
	return j.rpc.Call("RPC.SetMap", m, es)
}

func (j jRPC) SetServerMap(serverID, mapID int) error {
	return j.rpc.Call("RPC.SetServerMap", [2]int{serverID, mapID}, es)
}

func (j jRPC) ServerProperties(id int) (map[string]string, error) {
	sp := make(map[string]string)
	err := j.rpc.Call("RPC.ServerProperties", id, &sp)
	return sp, err
}

func (j jRPC) SetServerProperties(id int, properties map[string]string) error {
	return j.rpc.Call("RPC.SetServerProperties", data.ServerProperties{id, properties}, es)
}

func (j jRPC) MapProperties(id int) (map[string]string, error) {
	mp := make(map[string]string)
	err := j.rpc.Call("RPC.MapProperties", id, &mp)
	return mp, err
}

func (j jRPC) SetMapProperties(id int, properties map[string]string) error {
	return j.rpc.Call("RPC.SetMapProperties", data.ServerProperties{id, properties}, es)
}

func (j jRPC) RemoveServer(id int) error {
	return j.rpc.Call("RPC.RemoveServer", id, es)
}

func (j jRPC) RemoveMap(id int) error {
	return j.rpc.Call("RPC.RemoveMap", id, es)
}

func (j jRPC) StartServer(id int) error {
	return j.rpc.Call("RPC.StartServer", id, es)
}

func (j jRPC) StopServer(id int) error {
	return j.rpc.Call("RPC.StopServer", id, es)
}

func (j jRPC) CreateDefaultMap(d data.DefaultMap) error {
	return j.rpc.Call("RPC.CreateDefaultMap", d, es)
}

func (j jRPC) CreateSuperflatMap(d data.SuperFlatMap) error {
	return j.rpc.Call("RPC.CreateSuperflatMap", d, es)
}

func (j jRPC) CreateCustomMap(d data.CustomMap) error {
	return j.rpc.Call("RPC.CreateCustomMap", d, es)
}
<|endoftext|>