<commit_before>package service

import (
	"bytes"
	"context"
	"fmt"
	"net"
	"net/http"
	"strconv"
	"time"

	"github.com/onsi/ginkgo"

	v1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/client-go/kubernetes/scheme"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/events"
	"k8s.io/kubernetes/test/e2e/framework"
	"k8s.io/kubernetes/test/e2e/framework/service"
	"k8s.io/kubernetes/test/e2e/upgrades"

	"github.com/openshift/origin/pkg/monitor"
	"github.com/openshift/origin/test/extended/util/disruption"
)

// UpgradeTest tests that a service is available before, during, and
// after a cluster upgrade.
type UpgradeTest struct {
	jig        *service.TestJig
	tcpService *v1.Service
}

func (UpgradeTest) Name() string { return "k8s-service-lb-available" }
func (UpgradeTest) DisplayName() string {
	return "Application behind service load balancer with PDB is not disrupted"
}

func shouldTestPDBs() bool { return true }

// Setup creates a service with a load balancer and makes sure it's reachable.
func (t *UpgradeTest) Setup(f *framework.Framework) {
	serviceName := "service-test"
	jig := service.NewTestJig(f.ClientSet, f.Namespace.Name, serviceName)

	ns := f.Namespace
	cs := f.ClientSet

	ginkgo.By("creating a TCP service " + serviceName + " with type=LoadBalancer in namespace " + ns.Name)
	tcpService, err := jig.CreateTCPService(func(s *v1.Service) {
		s.Spec.Type = v1.ServiceTypeLoadBalancer
		if s.Annotations == nil {
			s.Annotations = make(map[string]string)
		}
		// We tune the LB checks to match the longest intervals available so that interactions between
		// upgrading components and the service are more obvious.
		// - AWS allows configuration, default is 70s (6 failed with 10s interval in 1.17) set to match GCP
		s.Annotations["service.beta.kubernetes.io/aws-load-balancer-healthcheck-interval"] = "8"
		s.Annotations["service.beta.kubernetes.io/aws-load-balancer-healthcheck-unhealthy-threshold"] = "3"
		s.Annotations["service.beta.kubernetes.io/aws-load-balancer-healthcheck-healthy-threshold"] = "2"
		// - Azure is hardcoded to 15s (2 failed with 5s interval in 1.17) and is sufficient
		// - GCP has a non-configurable interval of 32s (3 failed health checks with 8s interval in 1.17)
		//   - thus pods need to stay up for > 32s, so pod shutdown period will will be 45s
	})
	framework.ExpectNoError(err)
	tcpService, err = jig.WaitForLoadBalancer(service.GetServiceLoadBalancerCreationTimeout(cs))
	framework.ExpectNoError(err)

	// Get info to hit it with
	tcpIngressIP := service.GetIngressPoint(&tcpService.Status.LoadBalancer.Ingress[0])
	svcPort := int(tcpService.Spec.Ports[0].Port)

	ginkgo.By("creating RC to be part of service " + serviceName)
	rc, err := jig.Run(func(rc *v1.ReplicationController) {
		// ensure the pod waits long enough for most LBs to take it out of rotation, which has to be
		// longer than the LB failed health check interval
		rc.Spec.Template.Spec.Containers[0].Lifecycle = &v1.Lifecycle{
			PreStop: &v1.Handler{
				Exec: &v1.ExecAction{Command: []string{"sleep", "45"}},
			},
		}
		// ensure the pod is not forcibly deleted at 30s, but waits longer than the graceful sleep
		minute := int64(60)
		rc.Spec.Template.Spec.TerminationGracePeriodSeconds = &minute

		jig.AddRCAntiAffinity(rc)
	})
	framework.ExpectNoError(err)

	if shouldTestPDBs() {
		ginkgo.By("creating a PodDisruptionBudget to cover the ReplicationController")
		_, err = jig.CreatePDB(rc)
		framework.ExpectNoError(err)
	}

	// Hit it once before considering ourselves ready
	ginkgo.By("hitting pods through the service's LoadBalancer")
	timeout := service.LoadBalancerLagTimeoutAWS
	service.TestReachableHTTP(tcpIngressIP, svcPort, timeout)

	t.jig = jig
	t.tcpService = tcpService
}

// Test runs a connectivity check to the service.
func (t *UpgradeTest) Test(f *framework.Framework, done <-chan struct{}, upgrade upgrades.UpgradeType) {
	client, err := framework.LoadClientset()
	framework.ExpectNoError(err)

	stopCh := make(chan struct{})
	defer close(stopCh)
	newBroadcaster := events.NewBroadcaster(&events.EventSinkImpl{Interface: client.EventsV1beta1().Events("")})
	r := newBroadcaster.NewRecorder(scheme.Scheme, "openshift.io/upgrade-test-service")
	newBroadcaster.StartRecordingToSink(stopCh)

	ginkgo.By("continuously hitting pods through the service's LoadBalancer")

	ctx, cancel := context.WithCancel(context.Background())
	m := monitor.NewMonitorWithInterval(1 * time.Second)
	err = startEndpointMonitoring(ctx, m, t.tcpService, r)
	framework.ExpectNoError(err, "unable to monitor API")

	start := time.Now()
	m.StartSampling(ctx)

	// wait to ensure API is still up after the test ends
	<-done
	ginkgo.By("waiting for any post disruption failures")
	time.Sleep(15 * time.Second)
	cancel()
	end := time.Now()

	disruption.ExpectNoDisruption(f, 0.02, end.Sub(start), m.Events(time.Time{}, time.Time{}), "Service was unreachable during disruption")

	// verify finalizer behavior
	defer func() {
		ginkgo.By("Check that service can be deleted with finalizer")
		service.WaitForServiceDeletedWithFinalizer(t.jig.Client, t.tcpService.Namespace, t.tcpService.Name)
	}()
	ginkgo.By("Check that finalizer is present on loadBalancer type service")
	service.WaitForServiceUpdatedWithFinalizer(t.jig.Client, t.tcpService.Namespace, t.tcpService.Name, true)
}

// Teardown cleans up any remaining resources.
func (t *UpgradeTest) Teardown(f *framework.Framework) {
	// rely on the namespace deletion to clean up everything
}

func startEndpointMonitoring(ctx context.Context, m *monitor.Monitor, svc *v1.Service, r events.EventRecorder) error {
	tcpIngressIP := service.GetIngressPoint(&svc.Status.LoadBalancer.Ingress[0])
	svcPort := int(svc.Spec.Ports[0].Port)

	// this client reuses connections and detects abrupt breaks
	continuousClient, err := rest.UnversionedRESTClientFor(&rest.Config{
		Host:    fmt.Sprintf("http://%s", net.JoinHostPort(tcpIngressIP, strconv.Itoa(svcPort))),
		Timeout: 10 * time.Second,
		Transport: &http.Transport{
			Dial: (&net.Dialer{
				Timeout: 15 * time.Second,
			}).Dial,
			TLSHandshakeTimeout: 15 * time.Second,
		},
		ContentConfig: rest.ContentConfig{
			NegotiatedSerializer: runtime.NewSimpleNegotiatedSerializer(scheme.Codecs.SupportedMediaTypes()[0]),
		},
	})
	if err != nil {
		return err
	}
	m.AddSampler(
		monitor.StartSampling(ctx, m, time.Second, func(previous bool) (condition *monitor.Condition, next bool) {
			data, err := continuousClient.Get().AbsPath("echo").Param("msg", "Hello").DoRaw()
			if err == nil && !bytes.Contains(data, []byte("Hello")) {
				err = fmt.Errorf("service returned success but did not contain the correct body contents: %q", string(data))
			}
			switch {
			case err == nil && !previous:
				condition = &monitor.Condition{
					Level:   monitor.Info,
					Locator: locateService(svc),
					Message: "Service started responding to GET requests on reused connections",
				}
			case err != nil && previous:
				framework.Logf("Service %s is unreachable on reused connections: %v", svc.Name, err)
				r.Eventf(&v1.ObjectReference{Kind: "Service", Namespace: "kube-system", Name: "service-upgrade-test"}, nil, v1.EventTypeWarning, "Unreachable", "detected", "on reused connections")
				condition = &monitor.Condition{
					Level:   monitor.Error,
					Locator: locateService(svc),
					Message: "Service stopped responding to GET requests on reused connections",
				}
			case err != nil:
				framework.Logf("Service %s is unreachable on reused connections: %v", svc.Name, err)
			}
			return condition, err == nil
		}).ConditionWhenFailing(&monitor.Condition{
			Level:   monitor.Error,
			Locator: locateService(svc),
			Message: "Service is not responding to GET requests on reused connections",
		}),
	)

	// this client creates fresh connections and detects failure to establish connections
	client, err := rest.UnversionedRESTClientFor(&rest.Config{
		Host:    fmt.Sprintf("http://%s", net.JoinHostPort(tcpIngressIP, strconv.Itoa(svcPort))),
		Timeout: 10 * time.Second,
		Transport: &http.Transport{
			Dial: (&net.Dialer{
				Timeout:   15 * time.Second,
				KeepAlive: -1,
			}).Dial,
			TLSHandshakeTimeout: 15 * time.Second,
			IdleConnTimeout:     15 * time.Second,
			DisableKeepAlives:   true,
		},
		ContentConfig: rest.ContentConfig{
			NegotiatedSerializer: runtime.NewSimpleNegotiatedSerializer(scheme.Codecs.SupportedMediaTypes()[0]),
		},
	})
	if err != nil {
		return err
	}
	m.AddSampler(
		monitor.StartSampling(ctx, m, time.Second, func(previous bool) (condition *monitor.Condition, next bool) {
			data, err := client.Get().AbsPath("echo").Param("msg", "Hello").DoRaw()
			if err == nil && !bytes.Contains(data, []byte("Hello")) {
				err = fmt.Errorf("service returned success but did not contain the correct body contents: %q", string(data))
			}
			switch {
			case err == nil && !previous:
				condition = &monitor.Condition{
					Level:   monitor.Info,
					Locator: locateService(svc),
					Message: "Service started responding to GET requests over new connections",
				}
			case err != nil && previous:
				framework.Logf("Service %s is unreachable on new connections: %v", svc.Name, err)
				r.Eventf(&v1.ObjectReference{Kind: "Service", Namespace: "kube-system", Name: "service-upgrade-test"}, nil, v1.EventTypeWarning, "Unreachable", "detected", "on new connections")
				condition = &monitor.Condition{
					Level:   monitor.Error,
					Locator: locateService(svc),
					Message: "Service stopped responding to GET requests over new connections",
				}
			case err != nil:
				framework.Logf("Service %s is unreachable on new connections: %v", svc.Name, err)
			}
			return condition, err == nil
		}).ConditionWhenFailing(&monitor.Condition{
			Level:   monitor.Error,
			Locator: locateService(svc),
			Message: "Service is not responding to GET requests over new connections",
		}),
	)
	return nil
}

func locateService(svc *v1.Service) string {
	return fmt.Sprintf("ns/%s svc/%s", svc.Namespace, svc.Name)
}
<commit_msg>test: Ensure the upgrade test LB remains available<commit_after>package service

import (
	"bytes"
	"context"
	"fmt"
	"net"
	"net/http"
	"strconv"
	"time"

	"github.com/onsi/ginkgo"

	v1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/client-go/kubernetes/scheme"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/events"
	"k8s.io/kubernetes/test/e2e/framework"
	"k8s.io/kubernetes/test/e2e/framework/service"
	"k8s.io/kubernetes/test/e2e/upgrades"

	"github.com/openshift/origin/pkg/monitor"
	"github.com/openshift/origin/test/extended/util/disruption"
)

// UpgradeTest tests that a service is available before, during, and
// after a cluster upgrade.
type UpgradeTest struct {
	jig        *service.TestJig
	tcpService *v1.Service
}

func (UpgradeTest) Name() string { return "k8s-service-lb-available" }
func (UpgradeTest) DisplayName() string {
	return "Application behind service load balancer with PDB is not disrupted"
}

func shouldTestPDBs() bool { return true }

// Setup creates a service with a load balancer and makes sure it's reachable.
func (t *UpgradeTest) Setup(f *framework.Framework) {
	serviceName := "service-test"
	jig := service.NewTestJig(f.ClientSet, f.Namespace.Name, serviceName)

	ns := f.Namespace
	cs := f.ClientSet

	ginkgo.By("creating a TCP service " + serviceName + " with type=LoadBalancer in namespace " + ns.Name)
	tcpService, err := jig.CreateTCPService(func(s *v1.Service) {
		s.Spec.Type = v1.ServiceTypeLoadBalancer
		if s.Annotations == nil {
			s.Annotations = make(map[string]string)
		}
		// We tune the LB checks to match the longest intervals available so that interactions between
		// upgrading components and the service are more obvious.
		// - AWS allows configuration, default is 70s (6 failed with 10s interval in 1.17) set to match GCP
		s.Annotations["service.beta.kubernetes.io/aws-load-balancer-healthcheck-interval"] = "8"
		s.Annotations["service.beta.kubernetes.io/aws-load-balancer-healthcheck-unhealthy-threshold"] = "3"
		s.Annotations["service.beta.kubernetes.io/aws-load-balancer-healthcheck-healthy-threshold"] = "2"
		// - Azure is hardcoded to 15s (2 failed with 5s interval in 1.17) and is sufficient
		// - GCP has a non-configurable interval of 32s (3 failed health checks with 8s interval in 1.17)
		//   - thus pods need to stay up for > 32s, so pod shutdown period will will be 45s
	})
	framework.ExpectNoError(err)
	tcpService, err = jig.WaitForLoadBalancer(service.GetServiceLoadBalancerCreationTimeout(cs))
	framework.ExpectNoError(err)

	// Get info to hit it with
	tcpIngressIP := service.GetIngressPoint(&tcpService.Status.LoadBalancer.Ingress[0])
	svcPort := int(tcpService.Spec.Ports[0].Port)

	ginkgo.By("creating RC to be part of service " + serviceName)
	rc, err := jig.Run(func(rc *v1.ReplicationController) {
		// ensure the pod waits long enough for most LBs to take it out of rotation, which has to be
		// longer than the LB failed health check interval
		rc.Spec.Template.Spec.Containers[0].Lifecycle = &v1.Lifecycle{
			PreStop: &v1.Handler{
				Exec: &v1.ExecAction{Command: []string{"sleep", "45"}},
			},
		}
		// ensure the pod is not forcibly deleted at 30s, but waits longer than the graceful sleep
		minute := int64(60)
		rc.Spec.Template.Spec.TerminationGracePeriodSeconds = &minute

		jig.AddRCAntiAffinity(rc)
	})
	framework.ExpectNoError(err)

	if shouldTestPDBs() {
		ginkgo.By("creating a PodDisruptionBudget to cover the ReplicationController")
		_, err = jig.CreatePDB(rc)
		framework.ExpectNoError(err)
	}

	// Hit it once before considering ourselves ready
	ginkgo.By("hitting pods through the service's LoadBalancer")
	timeout := service.LoadBalancerLagTimeoutAWS
	// require five passing requests to continue (in case the SLB becomes available and then degrades)
	for i := 0; i < 5; i++ {
		service.TestReachableHTTP(tcpIngressIP, svcPort, timeout)
	}

	t.jig = jig
	t.tcpService = tcpService
}

// Test runs a connectivity check to the service.
func (t *UpgradeTest) Test(f *framework.Framework, done <-chan struct{}, upgrade upgrades.UpgradeType) {
	client, err := framework.LoadClientset()
	framework.ExpectNoError(err)

	stopCh := make(chan struct{})
	defer close(stopCh)
	newBroadcaster := events.NewBroadcaster(&events.EventSinkImpl{Interface: client.EventsV1beta1().Events("")})
	r := newBroadcaster.NewRecorder(scheme.Scheme, "openshift.io/upgrade-test-service")
	newBroadcaster.StartRecordingToSink(stopCh)

	ginkgo.By("continuously hitting pods through the service's LoadBalancer")

	ctx, cancel := context.WithCancel(context.Background())
	m := monitor.NewMonitorWithInterval(1 * time.Second)
	err = startEndpointMonitoring(ctx, m, t.tcpService, r)
	framework.ExpectNoError(err, "unable to monitor API")

	start := time.Now()
	m.StartSampling(ctx)

	// wait to ensure API is still up after the test ends
	<-done
	ginkgo.By("waiting for any post disruption failures")
	time.Sleep(15 * time.Second)
	cancel()
	end := time.Now()

	disruption.ExpectNoDisruption(f, 0.02, end.Sub(start), m.Events(time.Time{}, time.Time{}), "Service was unreachable during disruption")

	// verify finalizer behavior
	defer func() {
		ginkgo.By("Check that service can be deleted with finalizer")
		service.WaitForServiceDeletedWithFinalizer(t.jig.Client, t.tcpService.Namespace, t.tcpService.Name)
	}()
	ginkgo.By("Check that finalizer is present on loadBalancer type service")
	service.WaitForServiceUpdatedWithFinalizer(t.jig.Client, t.tcpService.Namespace, t.tcpService.Name, true)
}

// Teardown cleans up any remaining resources.
func (t *UpgradeTest) Teardown(f *framework.Framework) {
	// rely on the namespace deletion to clean up everything
}

func startEndpointMonitoring(ctx context.Context, m *monitor.Monitor, svc *v1.Service, r events.EventRecorder) error {
	tcpIngressIP := service.GetIngressPoint(&svc.Status.LoadBalancer.Ingress[0])
	svcPort := int(svc.Spec.Ports[0].Port)

	// this client reuses connections and detects abrupt breaks
	continuousClient, err := rest.UnversionedRESTClientFor(&rest.Config{
		Host:    fmt.Sprintf("http://%s", net.JoinHostPort(tcpIngressIP, strconv.Itoa(svcPort))),
		Timeout: 10 * time.Second,
		Transport: &http.Transport{
			Dial: (&net.Dialer{
				Timeout: 15 * time.Second,
			}).Dial,
			TLSHandshakeTimeout: 15 * time.Second,
		},
		ContentConfig: rest.ContentConfig{
			NegotiatedSerializer: runtime.NewSimpleNegotiatedSerializer(scheme.Codecs.SupportedMediaTypes()[0]),
		},
	})
	if err != nil {
		return err
	}
	m.AddSampler(
		monitor.StartSampling(ctx, m, time.Second, func(previous bool) (condition *monitor.Condition, next bool) {
			data, err := continuousClient.Get().AbsPath("echo").Param("msg", "Hello").DoRaw()
			if err == nil && !bytes.Contains(data, []byte("Hello")) {
				err = fmt.Errorf("service returned success but did not contain the correct body contents: %q", string(data))
			}
			switch {
			case err == nil && !previous:
				condition = &monitor.Condition{
					Level:   monitor.Info,
					Locator: locateService(svc),
					Message: "Service started responding to GET requests on reused connections",
				}
			case err != nil && previous:
				framework.Logf("Service %s is unreachable on reused connections: %v", svc.Name, err)
				r.Eventf(&v1.ObjectReference{Kind: "Service", Namespace: "kube-system", Name: "service-upgrade-test"}, nil, v1.EventTypeWarning, "Unreachable", "detected", "on reused connections")
				condition = &monitor.Condition{
					Level:   monitor.Error,
					Locator: locateService(svc),
					Message: "Service stopped responding to GET requests on reused connections",
				}
			case err != nil:
				framework.Logf("Service %s is unreachable on reused connections: %v", svc.Name, err)
			}
			return condition, err == nil
		}).ConditionWhenFailing(&monitor.Condition{
			Level:   monitor.Error,
			Locator: locateService(svc),
			Message: "Service is not responding to GET requests on reused connections",
		}),
	)

	// this client creates fresh connections and detects failure to establish connections
	client, err := rest.UnversionedRESTClientFor(&rest.Config{
		Host:    fmt.Sprintf("http://%s", net.JoinHostPort(tcpIngressIP, strconv.Itoa(svcPort))),
		Timeout: 10 * time.Second,
		Transport: &http.Transport{
			Dial: (&net.Dialer{
				Timeout:   15 * time.Second,
				KeepAlive: -1,
			}).Dial,
			TLSHandshakeTimeout: 15 * time.Second,
			IdleConnTimeout:     15 * time.Second,
			DisableKeepAlives:   true,
		},
		ContentConfig: rest.ContentConfig{
			NegotiatedSerializer: runtime.NewSimpleNegotiatedSerializer(scheme.Codecs.SupportedMediaTypes()[0]),
		},
	})
	if err != nil {
		return err
	}
	m.AddSampler(
		monitor.StartSampling(ctx, m, time.Second, func(previous bool) (condition *monitor.Condition, next bool) {
			data, err := client.Get().AbsPath("echo").Param("msg", "Hello").DoRaw()
			if err == nil && !bytes.Contains(data, []byte("Hello")) {
				err = fmt.Errorf("service returned success but did not contain the correct body contents: %q", string(data))
			}
			switch {
			case err == nil && !previous:
				condition = &monitor.Condition{
					Level:   monitor.Info,
					Locator: locateService(svc),
					Message: "Service started responding to GET requests over new connections",
				}
			case err != nil && previous:
				framework.Logf("Service %s is unreachable on new connections: %v", svc.Name, err)
				r.Eventf(&v1.ObjectReference{Kind: "Service", Namespace: "kube-system", Name: "service-upgrade-test"}, nil, v1.EventTypeWarning, "Unreachable", "detected", "on new connections")
				condition = &monitor.Condition{
					Level:   monitor.Error,
					Locator: locateService(svc),
					Message: "Service stopped responding to GET requests over new connections",
				}
			case err != nil:
				framework.Logf("Service %s is unreachable on new connections: %v", svc.Name, err)
			}
			return condition, err == nil
		}).ConditionWhenFailing(&monitor.Condition{
			Level:   monitor.Error,
			Locator: locateService(svc),
			Message: "Service is not responding to GET requests over new connections",
		}),
	)
	return nil
}

func locateService(svc *v1.Service) string {
	return fmt.Sprintf("ns/%s svc/%s", svc.Namespace, svc.Name)
}
<|endoftext|>


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

package gb

import (
	"errors"
	"fmt"
	"go/ast"
	"go/build"
	"go/doc"
	"go/parser"
	"go/token"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"sort"
	"strings"
	"sync"

	"github.com/rogpeppe/godef/go/types"
)

func FindGbProject(path string) (string, error) {
	if path == "" {
		return "", fmt.Errorf("project root is blank")
	}
	start := path
	for path != filepath.Dir(path) {
		root := filepath.Join(path, "src")
		if _, err := os.Stat(root); err != nil {
			if os.IsNotExist(err) {
				path = filepath.Dir(path)
				continue
			}
			return "", err
		}
		return path, nil
	}

	return "", fmt.Errorf(`could not find project root in "%s" or its parents`, start)
}

// GoPath returns a GOPATH for path p.
func GoPath(p string) string {
	goPath := os.Getenv("GOPATH")
	p = filepath.Clean(p)

	for _, root := range filepath.SplitList(goPath) {
		if strings.HasPrefix(p, filepath.Join(root, "src")+string(filepath.Separator)) {
			return goPath
		}
	}

	project, err := FindGbProject(p)
	if err == nil {
		parent, child := filepath.Split(project)
		if child == "vendor" {
			return filepath.Join(parent, "vendor") + string(filepath.ListSeparator) + goPath
		}
		return project + string(filepath.ListSeparator) +
			filepath.Join(project, "vendor") + string(filepath.ListSeparator) + goPath
	}

	return goPath
}

var goBuildDefaultMu sync.Mutex

// WithGoBuildForPath sets the go/build Default.GOPATH to GoPath(p) under a
// mutex. The returned function restores Default.GOPATH to its original value
// and unlocks the mutex.
//
// This function intended to be used to the golang.org/x/tools/imports and
// other packages that use go/build Default.
func WithGoBuildForPath(p string) func() {
	goBuildDefaultMu.Lock()
	original := build.Default.GOPATH
	build.Default.GOPATH = GoPath(p)
	types.GoPath = []string{build.Default.GOPATH}
	return func() {
		build.Default.GOPATH = original
		types.GoPath = []string{original}
		goBuildDefaultMu.Unlock()
	}
}

// Package represents a Go package.
type Package struct {
	FSet     *token.FileSet
	Build    *build.Package
	AST      *ast.Package
	Doc      *doc.Package
	Examples []*doc.Example
	Errors   []error
}

// Flags for LoadPackage.
const (
	LoadDoc = 1 << iota
	LoadExamples
	LoadUnexported
)

// LoadPackage Import returns details about the Go package named by the import
// path, interpreting local import paths relative to the srcDir directory.
func LoadPackage(importPath string, srcDir string, flags int) (*Package, error) {
	bpkg, err := build.Default.Import(importPath, srcDir, build.ImportComment)
	if _, ok := err.(*build.NoGoError); ok {
		return &Package{Build: bpkg}, nil
	}
	if err != nil {
		return nil, err
	}

	pkg := &Package{
		FSet:  token.NewFileSet(),
		Build: bpkg,
	}

	files := make(map[string]*ast.File)
	for _, name := range append(pkg.Build.GoFiles, pkg.Build.CgoFiles...) {
		file, err := pkg.parseFile(name)
		if err != nil {
			pkg.Errors = append(pkg.Errors, err)
			continue
		}
		files[name] = file
	}

	pkg.AST, _ = ast.NewPackage(pkg.FSet, files, simpleImporter, nil)

	if flags&LoadDoc != 0 {
		mode := doc.Mode(0)
		if pkg.Build.ImportPath == "builtin" || flags&LoadUnexported != 0 {
			mode |= doc.AllDecls
		}
		pkg.Doc = doc.New(pkg.AST, pkg.Build.ImportPath, mode)
		if pkg.Build.ImportPath == "builtin" {
			for _, t := range pkg.Doc.Types {
				pkg.Doc.Funcs = append(pkg.Doc.Funcs, t.Funcs...)
				t.Funcs = nil
			}
			sort.Sort(byFuncName(pkg.Doc.Funcs))
		}
	}

	if flags&LoadExamples != 0 {
		for _, name := range append(pkg.Build.TestGoFiles, pkg.Build.XTestGoFiles...) {
			file, err := pkg.parseFile(name)
			if err != nil {
				pkg.Errors = append(pkg.Errors, err)
				continue
			}
			pkg.Examples = append(pkg.Examples, doc.Examples(file)...)
		}
	}

	return pkg, nil
}

type byFuncName []*doc.Func

func (s byFuncName) Len() int           { return len(s) }
func (s byFuncName) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s byFuncName) Less(i, j int) bool { return s[i].Name < s[j].Name }

func (pkg *Package) parseFile(name string) (*ast.File, error) {
	p, err := ioutil.ReadFile(filepath.Join(pkg.Build.Dir, name))
	if err != nil {
		return nil, err
	}
	// overwrite //line comments
	for _, m := range linePat.FindAllIndex(p, -1) {
		for i := m[0] + 2; i < m[1]; i++ {
			p[i] = ' '
		}
	}
	return parser.ParseFile(pkg.FSet, name, p, parser.ParseComments)
}

var linePat = regexp.MustCompile(`(?m)^//line .*$`)

func simpleImporter(imports map[string]*ast.Object, path string) (*ast.Object, error) {
	pkg := imports[path]
	if pkg != nil {
		return pkg, nil
	}

	n := GuessPackageNameFromPath(path)
	if n == "" {
		return nil, errors.New("package not found")
	}

	pkg = ast.NewObj(ast.Pkg, n)
	pkg.Data = ast.NewScope(nil)
	imports[path] = pkg
	return pkg, nil
}

var packageNamePats = []*regexp.Regexp{
	// Last element with .suffix removed.
	regexp.MustCompile(`/([^-./]+)[-.](?:git|svn|hg|bzr|v\d+)$`),

	// Last element with "go" prefix or suffix removed.
	regexp.MustCompile(`/([^-./]+)[-.]go$`),
	regexp.MustCompile(`/go[-.]([^-./]+)$`),

	// It's also common for the last element of the path to contain an
	// extra "go" prefix, but not always. TODO: examine unresolved ids to
	// detect when trimming the "go" prefix is appropriate.

	// Last component of path.
	regexp.MustCompile(`([^/]+)$`),
}

// GuessPackageNameFromPath guesses the package name from the package path.
func GuessPackageNameFromPath(path string) string {
	// Guess the package name without importing it.
	for _, pat := range packageNamePats {
		m := pat.FindStringSubmatch(path)
		if m != nil {
			return m[1]
		}
	}
	return ""
}
<commit_msg>Remove set types.GoPath, Add GOROOT, Fix project path<commit_after>// Copyright 2015 Gary Burd. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package gb

import (
	"errors"
	"fmt"
	"go/ast"
	"go/build"
	"go/doc"
	"go/parser"
	"go/token"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"sort"
	"strings"
	"sync"
)

func FindGbProject(path string) (string, error) {
	if path == "" {
		return "", fmt.Errorf("project root is blank")
	}
	start := path
	for path != filepath.Dir(path) {
		root := filepath.Join(path, "src")
		if _, err := os.Stat(root); err != nil {
			if os.IsNotExist(err) {
				path = filepath.Dir(path)
				continue
			}
			return "", err
		}
		return path, nil
	}

	return "", fmt.Errorf(`could not find project root in "%s" or its parents`, start)
}

// GoPath returns a GOPATH for path p.
func GoPath(p string) string {
	goPath := os.Getenv("GOPATH")
	r := runtime.GOROOT()
	if r != "" {
		goPath = goPath + string(filepath.ListSeparator) + r
	}

	p = filepath.Clean(p)

	for _, root := range filepath.SplitList(goPath) {
		if strings.HasPrefix(p, filepath.Join(root, "src")+string(filepath.Separator)) {
			return goPath
		}
	}

	project, err := FindGbProject(p)
	if err == nil {
		parent, child := filepath.Split(project)
		if child == "vendor" {
			project = parent[:len(parent)-1]
		}
		return project + string(filepath.ListSeparator) +
			filepath.Join(project, "vendor") + string(filepath.ListSeparator) + goPath
	}

	return goPath
}

var goBuildDefaultMu sync.Mutex

// WithGoBuildForPath sets the go/build Default.GOPATH to GoPath(p) under a
// mutex. The returned function restores Default.GOPATH to its original value
// and unlocks the mutex.
//
// This function intended to be used to the golang.org/x/tools/imports and
// other packages that use go/build Default.
func WithGoBuildForPath(p string) func() {
	dir, _ := filepath.Split(p)
	goBuildDefaultMu.Lock()
	original := build.Default.GOPATH
	build.Default.GOPATH = GoPath(dir)
	return func() {
		build.Default.GOPATH = original
		goBuildDefaultMu.Unlock()
	}
}

// Package represents a Go package.
type Package struct {
	FSet     *token.FileSet
	Build    *build.Package
	AST      *ast.Package
	Doc      *doc.Package
	Examples []*doc.Example
	Errors   []error
}

// Flags for LoadPackage.
const (
	LoadDoc = 1 << iota
	LoadExamples
	LoadUnexported
)

// LoadPackage Import returns details about the Go package named by the import
// path, interpreting local import paths relative to the srcDir directory.
func LoadPackage(importPath string, srcDir string, flags int) (*Package, error) {
	bpkg, err := build.Default.Import(importPath, srcDir, build.ImportComment)
	if _, ok := err.(*build.NoGoError); ok {
		return &Package{Build: bpkg}, nil
	}
	if err != nil {
		return nil, err
	}

	pkg := &Package{
		FSet:  token.NewFileSet(),
		Build: bpkg,
	}

	files := make(map[string]*ast.File)
	for _, name := range append(pkg.Build.GoFiles, pkg.Build.CgoFiles...) {
		file, err := pkg.parseFile(name)
		if err != nil {
			pkg.Errors = append(pkg.Errors, err)
			continue
		}
		files[name] = file
	}

	pkg.AST, _ = ast.NewPackage(pkg.FSet, files, simpleImporter, nil)

	if flags&LoadDoc != 0 {
		mode := doc.Mode(0)
		if pkg.Build.ImportPath == "builtin" || flags&LoadUnexported != 0 {
			mode |= doc.AllDecls
		}
		pkg.Doc = doc.New(pkg.AST, pkg.Build.ImportPath, mode)
		if pkg.Build.ImportPath == "builtin" {
			for _, t := range pkg.Doc.Types {
				pkg.Doc.Funcs = append(pkg.Doc.Funcs, t.Funcs...)
				t.Funcs = nil
			}
			sort.Sort(byFuncName(pkg.Doc.Funcs))
		}
	}

	if flags&LoadExamples != 0 {
		for _, name := range append(pkg.Build.TestGoFiles, pkg.Build.XTestGoFiles...) {
			file, err := pkg.parseFile(name)
			if err != nil {
				pkg.Errors = append(pkg.Errors, err)
				continue
			}
			pkg.Examples = append(pkg.Examples, doc.Examples(file)...)
		}
	}

	return pkg, nil
}

type byFuncName []*doc.Func

func (s byFuncName) Len() int           { return len(s) }
func (s byFuncName) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s byFuncName) Less(i, j int) bool { return s[i].Name < s[j].Name }

func (pkg *Package) parseFile(name string) (*ast.File, error) {
	p, err := ioutil.ReadFile(filepath.Join(pkg.Build.Dir, name))
	if err != nil {
		return nil, err
	}
	// overwrite //line comments
	for _, m := range linePat.FindAllIndex(p, -1) {
		for i := m[0] + 2; i < m[1]; i++ {
			p[i] = ' '
		}
	}
	return parser.ParseFile(pkg.FSet, name, p, parser.ParseComments)
}

var linePat = regexp.MustCompile(`(?m)^//line .*$`)

func simpleImporter(imports map[string]*ast.Object, path string) (*ast.Object, error) {
	pkg := imports[path]
	if pkg != nil {
		return pkg, nil
	}

	n := GuessPackageNameFromPath(path)
	if n == "" {
		return nil, errors.New("package not found")
	}

	pkg = ast.NewObj(ast.Pkg, n)
	pkg.Data = ast.NewScope(nil)
	imports[path] = pkg
	return pkg, nil
}

var packageNamePats = []*regexp.Regexp{
	// Last element with .suffix removed.
	regexp.MustCompile(`/([^-./]+)[-.](?:git|svn|hg|bzr|v\d+)$`),

	// Last element with "go" prefix or suffix removed.
	regexp.MustCompile(`/([^-./]+)[-.]go$`),
	regexp.MustCompile(`/go[-.]([^-./]+)$`),

	// It's also common for the last element of the path to contain an
	// extra "go" prefix, but not always. TODO: examine unresolved ids to
	// detect when trimming the "go" prefix is appropriate.

	// Last component of path.
	regexp.MustCompile(`([^/]+)$`),
}

// GuessPackageNameFromPath guesses the package name from the package path.
func GuessPackageNameFromPath(path string) string {
	// Guess the package name without importing it.
	for _, pat := range packageNamePats {
		m := pat.FindStringSubmatch(path)
		if m != nil {
			return m[1]
		}
	}
	return ""
}
<|endoftext|>


<commit_before>package natsgw

import (
	"encoding/json"
	"time"

	"github.com/CyCoreSystems/ari"
	"github.com/CyCoreSystems/ari/client/nc"
)

func (srv *Server) bridge() {

	srv.subscribe("ari.bridges.all", func(_ string, _ []byte, reply Reply) {

		bx, err := srv.upstream.Bridge.List()
		if err != nil {
			reply(nil, err)
			return
		}

		var bridges []string
		for _, bridge := range bx {
			bridges = append(bridges, bridge.ID())
		}

		reply(bridges, nil)
	})

	srv.subscribe("ari.bridges.data.>", func(subj string, _ []byte, reply Reply) {
		name := subj[len("ari.bridges.data."):]
		bd, err := srv.upstream.Bridge.Data(name)
		reply(&bd, err)
		return
	})

	srv.subscribe("ari.bridges.create", func(subj string, data []byte, reply Reply) {

		var req nc.CreateBridgeRequest
		if err := json.Unmarshal(data, &req); err != nil {
			reply(nil, &decodingError{subj, err})
			return
		}

		bh, err := srv.upstream.Bridge.Create(req.ID, req.Type, req.Name)

		if err != nil {
			reply(nil, err)
			return
		}

		reply(bh.ID(), err)
	})

	srv.subscribe("ari.bridges.addChannel.>", func(subj string, data []byte, reply Reply) {
		name := subj[len("ari.bridges.addChannel."):]

		var channelID string
		if err := json.Unmarshal(data, &channelID); err != nil {
			reply(nil, &decodingError{subj, err})
			return
		}

		err := srv.upstream.Bridge.AddChannel(name, channelID)
		reply(nil, err)
	})

	srv.subscribe("ari.bridges.removeChannel.>", func(subj string, data []byte, reply Reply) {
		name := subj[len("ari.bridges.removeChannel."):]

		var channelID string
		if err := json.Unmarshal(data, &channelID); err != nil {
			reply(nil, &decodingError{subj, err})
			return
		}

		err := srv.upstream.Bridge.RemoveChannel(name, channelID)
		reply(nil, err)
	})

	srv.subscribe("ari.bridges.delete.>", func(subj string, _ []byte, reply Reply) {
		name := subj[len("ari.bridges.delete."):]
		err := srv.upstream.Bridge.Delete(name)
		reply(nil, err)
	})

	srv.subscribe("ari.bridges.play.>", func(subj string, data []byte, reply Reply) {
		name := subj[len("ari.bridges.play."):]

		var pr nc.PlayRequest
		if err := json.Unmarshal(data, &pr); err != nil {
			reply(nil, &decodingError{subj, err})
			return
		}

		_, err := srv.upstream.Bridge.Play(name, pr.PlaybackID, pr.MediaURI)
		reply(nil, err)
	})

	srv.subscribe("ari.bridges.record.>", func(subj string, data []byte, reply Reply) {
		name := subj[len("ari.bridges.record."):]

		var rr nc.RecordRequest
		if err := json.Unmarshal(data, &rr); err != nil {
			reply(nil, &decodingError{subj, err})
			return
		}

		var opts ari.RecordingOptions

		opts.Format = rr.Format
		opts.MaxDuration = time.Duration(rr.MaxDuration) * time.Second
		opts.MaxSilence = time.Duration(rr.MaxSilence) * time.Second
		opts.Exists = rr.IfExists
		opts.Beep = rr.Beep
		opts.Terminate = rr.TerminateOn

		_, err := srv.upstream.Bridge.Record(name, rr.Name, &opts)
		reply(nil, err)
	})
}
<commit_msg>natsgw - update bridge to use '*' wildcards'<commit_after>package natsgw

import (
	"encoding/json"
	"time"

	"github.com/CyCoreSystems/ari"
	"github.com/CyCoreSystems/ari/client/nc"
)

func (srv *Server) bridge() {

	srv.subscribe("ari.bridges.all", func(_ string, _ []byte, reply Reply) {

		bx, err := srv.upstream.Bridge.List()
		if err != nil {
			reply(nil, err)
			return
		}

		var bridges []string
		for _, bridge := range bx {
			bridges = append(bridges, bridge.ID())
		}

		reply(bridges, nil)
	})

	srv.subscribe("ari.bridges.data.*", func(subj string, _ []byte, reply Reply) {
		name := subj[len("ari.bridges.data."):]
		bd, err := srv.upstream.Bridge.Data(name)
		reply(&bd, err)
		return
	})

	srv.subscribe("ari.bridges.create", func(subj string, data []byte, reply Reply) {

		var req nc.CreateBridgeRequest
		if err := json.Unmarshal(data, &req); err != nil {
			reply(nil, &decodingError{subj, err})
			return
		}

		bh, err := srv.upstream.Bridge.Create(req.ID, req.Type, req.Name)

		if err != nil {
			reply(nil, err)
			return
		}

		reply(bh.ID(), err)
	})

	srv.subscribe("ari.bridges.addChannel.*", func(subj string, data []byte, reply Reply) {
		name := subj[len("ari.bridges.addChannel."):]

		var channelID string
		if err := json.Unmarshal(data, &channelID); err != nil {
			reply(nil, &decodingError{subj, err})
			return
		}

		err := srv.upstream.Bridge.AddChannel(name, channelID)
		reply(nil, err)
	})

	srv.subscribe("ari.bridges.removeChannel.*", func(subj string, data []byte, reply Reply) {
		name := subj[len("ari.bridges.removeChannel."):]

		var channelID string
		if err := json.Unmarshal(data, &channelID); err != nil {
			reply(nil, &decodingError{subj, err})
			return
		}

		err := srv.upstream.Bridge.RemoveChannel(name, channelID)
		reply(nil, err)
	})

	srv.subscribe("ari.bridges.delete.*", func(subj string, _ []byte, reply Reply) {
		name := subj[len("ari.bridges.delete."):]
		err := srv.upstream.Bridge.Delete(name)
		reply(nil, err)
	})

	srv.subscribe("ari.bridges.play.*", func(subj string, data []byte, reply Reply) {
		name := subj[len("ari.bridges.play."):]

		var pr nc.PlayRequest
		if err := json.Unmarshal(data, &pr); err != nil {
			reply(nil, &decodingError{subj, err})
			return
		}

		_, err := srv.upstream.Bridge.Play(name, pr.PlaybackID, pr.MediaURI)
		reply(nil, err)
	})

	srv.subscribe("ari.bridges.record.*", func(subj string, data []byte, reply Reply) {
		name := subj[len("ari.bridges.record."):]

		var rr nc.RecordRequest
		if err := json.Unmarshal(data, &rr); err != nil {
			reply(nil, &decodingError{subj, err})
			return
		}

		var opts ari.RecordingOptions

		opts.Format = rr.Format
		opts.MaxDuration = time.Duration(rr.MaxDuration) * time.Second
		opts.MaxSilence = time.Duration(rr.MaxSilence) * time.Second
		opts.Exists = rr.IfExists
		opts.Beep = rr.Beep
		opts.Terminate = rr.TerminateOn

		_, err := srv.upstream.Bridge.Record(name, rr.Name, &opts)
		reply(nil, err)
	})
}
<|endoftext|>


<commit_before>// Copyright 2013 The lime Authors.
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package commands

import (
	. "github.com/limetext/lime/backend"
	. "github.com/quarnster/util/text"
)

type (
	// The FindUnderExpandCommand extends the selection to the current word
	// if the current selection region is empty.
	// If one character or more is selected, the text buffer is scanned for
	// the next occurrence of the selection and that region too is added to
	// the selection set.
	FindUnderExpandCommand struct {
		DefaultCommand
	}
	// The SingleSelectionCommand merges multiple cursors
	// into a single one.
	SingleSelectionCommand struct {
		DefaultCommand
	}
	// The AllSelectionCommand selects the whole buffer of the current file
	AllSelectionCommand struct {
		DefaultCommand
	}
)

func (c *SingleSelectionCommand) Run(v *View, e *Edit) error {
	r := v.Sel().Get(0)
	v.Sel().Clear()
	v.Sel().Add(r)
	return nil
}

func (c *FindUnderExpandCommand) Run(v *View, e *Edit) error {
	sel := v.Sel()
	rs := sel.Regions()

	he := sel.HasEmpty()
	if he {
		for i, r := range rs {
			if r2 := v.Buffer().Word(r.A); r2.Size() > r.Size() {
				rs[i] = r2
			}
		}
		sel.Clear()
		sel.AddAll(rs)
		return nil
	}
	last := rs[len(rs)-1]
	b := v.Buffer()
	data := b.SubstrR(last)
	next := last
	size := last.Size()
	next.A += size
	next.B += size
	buf := b.SubstrR(Region{next.A, next.B})
	for next.End() < b.Size() {
		buf[size-1] = b.Index(next.B - 1)
		found := true
		for j, r := range buf {
			if r != data[j] {
				found = false
				break
			}
		}
		if found {
			sel.Add(next)
			break
		}
		copy(buf, buf[1:])
		next.A += 1
		next.B += 1
	}
	return nil
}

func (c *AllSelectionCommand) Run(v *View, e *Edit) error {
	r := Region{0, v.Buffer().Size()}
	v.Sel().Clear()
	v.Sel().Add(r)
	return nil
}

func init() {
	register([]Command{
		&FindUnderExpandCommand{},
		&SingleSelectionCommand{},
	})

	registerByName([]namedCmd{
		{"select_all", &AllSelectionCommand{}},
	})
}
<commit_msg>Rename AllSelectionCommand to SelectAllCommand.<commit_after>// Copyright 2013 The lime Authors.
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package commands

import (
	. "github.com/limetext/lime/backend"
	. "github.com/quarnster/util/text"
)

type (
	// The FindUnderExpandCommand extends the selection to the current word
	// if the current selection region is empty.
	// If one character or more is selected, the text buffer is scanned for
	// the next occurrence of the selection and that region too is added to
	// the selection set.
	FindUnderExpandCommand struct {
		DefaultCommand
	}
	// The SingleSelectionCommand merges multiple cursors
	// into a single one.
	SingleSelectionCommand struct {
		DefaultCommand
	}
	// The SelectAllCommand selects the whole buffer of the current file
	SelectAllCommand struct {
		DefaultCommand
	}
)

func (c *SingleSelectionCommand) Run(v *View, e *Edit) error {
	r := v.Sel().Get(0)
	v.Sel().Clear()
	v.Sel().Add(r)
	return nil
}

func (c *FindUnderExpandCommand) Run(v *View, e *Edit) error {
	sel := v.Sel()
	rs := sel.Regions()

	he := sel.HasEmpty()
	if he {
		for i, r := range rs {
			if r2 := v.Buffer().Word(r.A); r2.Size() > r.Size() {
				rs[i] = r2
			}
		}
		sel.Clear()
		sel.AddAll(rs)
		return nil
	}
	last := rs[len(rs)-1]
	b := v.Buffer()
	data := b.SubstrR(last)
	next := last
	size := last.Size()
	next.A += size
	next.B += size
	buf := b.SubstrR(Region{next.A, next.B})
	for next.End() < b.Size() {
		buf[size-1] = b.Index(next.B - 1)
		found := true
		for j, r := range buf {
			if r != data[j] {
				found = false
				break
			}
		}
		if found {
			sel.Add(next)
			break
		}
		copy(buf, buf[1:])
		next.A += 1
		next.B += 1
	}
	return nil
}

func (c *SelectAllCommand) Run(v *View, e *Edit) error {
	r := Region{0, v.Buffer().Size()}
	v.Sel().Clear()
	v.Sel().Add(r)
	return nil
}

func init() {
	register([]Command{
		&FindUnderExpandCommand{},
		&SingleSelectionCommand{},
		&SelectAllCommand{},
	})
}
<|endoftext|>


<commit_before>package eliteConfiguration

const (
	version = "0"
	release = "3"
	hotfix  = "0"
	feature = "8"
)

/**
Version get the complete Library's version
*/
func Version() string {
	return version + "." + release + "." + hotfix + "." + feature
}
<commit_msg>eliteConfiguration - Release (0.3)<commit_after>package eliteConfiguration

const (
	version = "0"
	release = "3"
	hotfix  = "0"
	feature = "0"
)

/**
Version get the complete Library's version
*/
func Version() string {
	return version + "." + release + "." + hotfix + "." + feature
}
<|endoftext|>


<commit_before>package router

// This file describes two routes that are used throughout the Melange System.

import (
	"errors"
	"fmt"
	"strings"

	"airdispat.ch/identity"
	"airdispat.ch/routing"
	"airdispat.ch/tracker"
	cache "github.com/huntaub/go-cache"
)

var routeCache *cache.Cache

// var cLock sync.RWMutex

var ServerKey *identity.Identity

type Router struct {
	Origin      *identity.Identity
	TrackerList []string
	Redirects   int
}

func (r *Router) HandleRedirect(name routing.LookupType, redirect routing.Redirect) (*identity.Address, error) {
	r.Redirects++
	if r.Redirects > 10 {
		return nil, errors.New("Too many redirects.")
	}
	data, err := r.LookupAlias(redirect.Alias, name)
	if err != nil {
		return nil, err
	}
	if data.String() != redirect.Fingerprint {
		return nil, errors.New("Redirected data doesn't have the same fingerprint.")
	}
	return data, nil
}

func (a *Router) LookupAlias(from string, name routing.LookupType) (*identity.Address, error) {
	test, stale := routeCache.Get(from)
	if !stale {
		return test.(*identity.Address), nil
	}

	if from[0] == '/' {
		return a.Lookup(from[1:], name)
	}
	comp := strings.Split(from, "@")
	if len(comp) != 2 {
		return nil, errors.New("Can't use lookup router without tracker address.")
	}

	url := tracker.GetTrackingServerLocationFromURL(comp[1])
	t := &tracker.Router{
		URL:        url,
		Origin:     a.Origin,
		Redirector: a,
	}

	addr, err := t.LookupAlias(comp[0], name)
	if err == nil {
		routeCache.Store(from, addr)
		routeCache.Store(addr.String(), addr)
		return addr, nil
	}
	return nil, err
}

func (a *Router) Lookup(from string, name routing.LookupType) (*identity.Address, error) {
	test, stale := routeCache.Get(from)
	if !stale {
		return test.(*identity.Address), nil
	}

	for _, v := range a.TrackerList {
		fmt.Println(v, ServerKey)
		a, err := (&tracker.Router{
			URL:        v,
			Origin:     ServerKey,
			Redirector: a,
		}).Lookup(from, name)
		if err == nil {
			routeCache.Store(from, a)
			routeCache.Store(a.String(), a)
			return a, nil
		}
	}
	return nil, errors.New("Couldn't find address in Trackers.")
}

func (a *Router) Register(key *identity.Identity, alias string, redirect map[string]routing.Redirect) error {
	var err error
	success := 0

	for _, v := range a.TrackerList {
		newErr := (&tracker.Router{
			Origin: a.Origin,
			URL:    v,
		}).Register(key, alias, redirect)
		if newErr == nil {
			success++
		} else {
			err = newErr
		}
	}

	if success == 0 && err != nil {
		return errors.New("All registration failed. Last Error: " + err.Error())
	} else {
		return nil
	}
}
<commit_msg>Fixed Errors in Router<commit_after>package router

// This file describes two routes that are used throughout the Melange System.

import (
	"errors"
	"fmt"
	"strings"
	"time"

	"airdispat.ch/identity"
	"airdispat.ch/routing"
	"airdispat.ch/tracker"
	cache "github.com/huntaub/go-cache"
)

var routeCache *cache.Cache = cache.NewCache(1 * time.Hour)
var knownTrackers []string = []string{"localhost:2048"}

// var cLock sync.RWMutex

var ServerKey *identity.Identity

type Router struct {
	Origin      *identity.Identity
	TrackerList []string
	Redirects   int
}

func (r *Router) HandleRedirect(name routing.LookupType, redirect routing.Redirect) (*identity.Address, error) {
	r.Redirects++
	if r.Redirects > 10 {
		return nil, errors.New("Too many redirects.")
	}
	data, err := r.LookupAlias(redirect.Alias, name)
	if err != nil {
		return nil, err
	}
	if data.String() != redirect.Fingerprint {
		return nil, errors.New("Redirected data doesn't have the same fingerprint.")
	}
	return data, nil
}

func (a *Router) LookupAlias(from string, name routing.LookupType) (*identity.Address, error) {
	key := fmt.Sprintf("%s:%s", from, name)
	test, stale := routeCache.Get(key)
	if !stale {
		return test.(*identity.Address), nil
	}

	if from == "" {
		return nil, errors.New("Can't lookup nothing.")
	}

	if from[0] == '/' {
		return a.Lookup(from[1:], name)
	}

	comp := strings.Split(from, "@")

	if len(comp) != 2 {
		return nil, errors.New("Can't use lookup router without tracker address.")
	}

	url := tracker.GetTrackingServerLocationFromURL(comp[1])

	t := &tracker.Router{
		URL:        url,
		Origin:     a.Origin,
		Redirector: a,
	}

	addr, err := t.LookupAlias(comp[0], name)
	if err == nil {
		routeCache.Store(key, addr)
		routeCache.Store(fmt.Sprintf("%s:%s", addr, name), addr)
		return addr, nil
	}
	return nil, err
}

func (a *Router) Lookup(from string, name routing.LookupType) (*identity.Address, error) {
	key := fmt.Sprintf("%s:%s", from, name)
	test, stale := routeCache.Get(key)
	if !stale {
		return test.(*identity.Address), nil
	}

	for _, v := range a.TrackerList {
		fmt.Println(v, ServerKey)
		a, err := (&tracker.Router{
			URL:        v,
			Origin:     ServerKey,
			Redirector: a,
		}).Lookup(from, name)
		if err == nil {
			routeCache.Store(key, a)
			routeCache.Store(fmt.Sprintf("%s:%s", a, name), a)
			return a, nil
		}
	}
	return nil, errors.New("Couldn't find address in Trackers.")
}

func (a *Router) Register(key *identity.Identity, alias string, redirect map[string]routing.Redirect) error {
	var err error
	success := 0

	for _, v := range a.TrackerList {
		newErr := (&tracker.Router{
			Origin: a.Origin,
			URL:    v,
		}).Register(key, alias, redirect)
		if newErr == nil {
			success++
		} else {
			err = newErr
		}
	}

	if success == 0 && err != nil {
		return errors.New("All registration failed. Last Error: " + err.Error())
	} else {
		return nil
	}
}
<|endoftext|>


<commit_before>// Copyright 2017 The OPA Authors.  All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.

// Package writer contains utilities for writing responses in the server.
package writer

import (
	"encoding/json"
	"net/http"

	"github.com/open-policy-agent/opa/ast"
	"github.com/open-policy-agent/opa/server/types"
	"github.com/open-policy-agent/opa/storage"
	"github.com/open-policy-agent/opa/topdown"
	"github.com/pkg/errors"
)

// ErrorAuto writes a response with status and code set automatically based on
// the type of err.
func ErrorAuto(w http.ResponseWriter, err error) {
	var prev error
	for curr := err; curr != prev; {
		if types.IsBadRequest(curr) {
			ErrorString(w, http.StatusBadRequest, types.CodeInvalidParameter, err)
			return
		}
		if types.IsWriteConflict(curr) {
			ErrorString(w, http.StatusNotFound, types.CodeResourceConflict, err)
			return
		}
		if topdown.IsError(curr) {
			Error(w, http.StatusInternalServerError, types.NewErrorV1(types.CodeInternal, types.MsgEvaluationError).WithError(curr))
		}
		if ast.IsError(ast.InputErr, curr) {
			Error(w, http.StatusBadRequest, types.NewErrorV1(types.CodeInvalidParameter, types.MsgInputDocError).WithError(curr))
			return
		}
		if storage.IsInvalidPatch(curr) {
			ErrorString(w, http.StatusBadRequest, types.CodeInvalidParameter, err)
			return
		}
		if storage.IsNotFound(curr) {
			ErrorString(w, http.StatusNotFound, types.CodeResourceNotFound, err)
			return
		}
		prev = curr
		curr = errors.Cause(prev)
	}
	ErrorString(w, http.StatusInternalServerError, types.CodeInternal, err)
}

// ErrorString writes a response with specified status, code, and message set to
// the the err's string representation.
func ErrorString(w http.ResponseWriter, status int, code string, err error) {
	Error(w, status, types.NewErrorV1(code, err.Error()))
}

// Error writes a response with specified status and error response.
func Error(w http.ResponseWriter, status int, err *types.ErrorV1) {
	headers := w.Header()
	headers.Add("Content-Type", "application/json")
	Bytes(w, status, err.Bytes())
}

// JSON writes a response with the specified status code and object. The object
// will be JSON serialized.
func JSON(w http.ResponseWriter, code int, v interface{}, pretty bool) {

	var bs []byte
	var err error

	if pretty {
		bs, err = json.MarshalIndent(v, "", "  ")
	} else {
		bs, err = json.Marshal(v)
	}

	if err != nil {
		ErrorAuto(w, err)
		return
	}
	headers := w.Header()
	headers.Add("Content-Type", "application/json")
	Bytes(w, code, bs)
}

// Bytes writes a response with the specified status code and bytes.
func Bytes(w http.ResponseWriter, code int, bs []byte) {
	w.WriteHeader(code)
	if code == 204 {
		return
	}
	w.Write(bs)
}
<commit_msg>Fix buggy usage of errors.Cause<commit_after>// Copyright 2017 The OPA Authors.  All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.

// Package writer contains utilities for writing responses in the server.
package writer

import (
	"encoding/json"
	"net/http"

	"github.com/open-policy-agent/opa/ast"
	"github.com/open-policy-agent/opa/server/types"
	"github.com/open-policy-agent/opa/storage"
	"github.com/open-policy-agent/opa/topdown"
)

// ErrorAuto writes a response with status and code set automatically based on
// the type of err.
func ErrorAuto(w http.ResponseWriter, err error) {
	if types.IsBadRequest(err) {
		ErrorString(w, http.StatusBadRequest, types.CodeInvalidParameter, err)
		return
	}

	if types.IsWriteConflict(err) {
		ErrorString(w, http.StatusNotFound, types.CodeResourceConflict, err)
		return
	}

	if topdown.IsError(err) {
		Error(w, http.StatusInternalServerError, types.NewErrorV1(types.CodeInternal, types.MsgEvaluationError).WithError(err))
		return
	}

	if ast.IsError(ast.InputErr, err) {
		Error(w, http.StatusBadRequest, types.NewErrorV1(types.CodeInvalidParameter, types.MsgInputDocError).WithError(err))
		return
	}

	if storage.IsInvalidPatch(err) {
		ErrorString(w, http.StatusBadRequest, types.CodeInvalidParameter, err)
		return
	}

	if storage.IsNotFound(err) {
		ErrorString(w, http.StatusNotFound, types.CodeResourceNotFound, err)
		return
	}

	ErrorString(w, http.StatusInternalServerError, types.CodeInternal, err)
}

// ErrorString writes a response with specified status, code, and message set to
// the the err's string representation.
func ErrorString(w http.ResponseWriter, status int, code string, err error) {
	Error(w, status, types.NewErrorV1(code, err.Error()))
}

// Error writes a response with specified status and error response.
func Error(w http.ResponseWriter, status int, err *types.ErrorV1) {
	headers := w.Header()
	headers.Add("Content-Type", "application/json")
	Bytes(w, status, err.Bytes())
}

// JSON writes a response with the specified status code and object. The object
// will be JSON serialized.
func JSON(w http.ResponseWriter, code int, v interface{}, pretty bool) {

	var bs []byte
	var err error

	if pretty {
		bs, err = json.MarshalIndent(v, "", "  ")
	} else {
		bs, err = json.Marshal(v)
	}

	if err != nil {
		ErrorAuto(w, err)
		return
	}
	headers := w.Header()
	headers.Add("Content-Type", "application/json")
	Bytes(w, code, bs)
}

// Bytes writes a response with the specified status code and bytes.
func Bytes(w http.ResponseWriter, code int, bs []byte) {
	w.WriteHeader(code)
	if code == 204 {
		return
	}
	w.Write(bs)
}
<|endoftext|>


<commit_before>package test

import (
	"crypto/tls"
	"math"
	"testing"
	"time"

	"github.com/eleniums/gohost"
	"github.com/eleniums/gohost/examples/test"
	pb "github.com/eleniums/gohost/examples/test/proto"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"

	assert "github.com/stretchr/testify/require"
)

func Test_Hoster_ListenAndServe_GRPC_Successful(t *testing.T) {
	// arrange
	service := test.NewService()
	grpcAddr := getAddr(t)

	expectedValue := "test"

	hoster := gohost.NewHoster()
	hoster.GRPCAddr = grpcAddr
	hoster.RegisterGRPCEndpoint(func(s *grpc.Server) {
		pb.RegisterTestServiceServer(s, service)
	})

	// act - start the service
	go hoster.ListenAndServe()

	// make sure service has time to start
	time.Sleep(serviceStartDelay)

	// call the service at the gRPC endpoint
	conn, err := grpc.Dial(grpcAddr, grpc.WithInsecure())
	assert.NoError(t, err)
	client := pb.NewTestServiceClient(conn)
	grpcReq := pb.SendRequest{
		Value: expectedValue,
	}
	grpcResp, err := client.Echo(context.Background(), &grpcReq)

	// assert
	assert.NoError(t, err)
	assert.NotNil(t, grpcResp)
	assert.Equal(t, expectedValue, grpcResp.Echo)
}

func Test_Hoster_ListenAndServe_GRPC_WithTLS(t *testing.T) {
	// arrange
	service := test.NewService()
	grpcAddr := getAddr(t)

	expectedValue := "test"

	hoster := gohost.NewHoster()
	hoster.GRPCAddr = grpcAddr
	hoster.RegisterGRPCEndpoint(func(s *grpc.Server) {
		pb.RegisterTestServiceServer(s, service)
	})

	hoster.CertFile = "./testdata/test.crt"
	hoster.KeyFile = "./testdata/test.key"

	// act - start the service
	go hoster.ListenAndServe()

	// make sure service has time to start
	time.Sleep(serviceStartDelay)

	// call the service at the gRPC endpoint
	conn, err := grpc.Dial(grpcAddr, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{InsecureSkipVerify: true})))
	assert.NoError(t, err)
	client := pb.NewTestServiceClient(conn)
	grpcReq := pb.SendRequest{
		Value: expectedValue,
	}
	grpcResp, err := client.Echo(context.Background(), &grpcReq)

	// assert
	assert.NoError(t, err)
	assert.NotNil(t, grpcResp)
	assert.Equal(t, expectedValue, grpcResp.Echo)
}

func Test_Hoster_ListenAndServe_GRPC_EmptyAddress(t *testing.T) {
	// arrange
	service := test.NewService()

	hoster := gohost.NewHoster()
	hoster.GRPCAddr = ""
	hoster.RegisterGRPCEndpoint(func(s *grpc.Server) {
		pb.RegisterTestServiceServer(s, service)
	})

	// act - start the service
	err := hoster.ListenAndServe()

	// assert
	assert.Error(t, err)
}

func Test_Hoster_ListenAndServe_GRPC_MaxRecvMsgSize_Pass(t *testing.T) {
	// arrange
	service := test.NewService()
	grpcAddr := getAddr(t)

	largeValue := string(make([]byte, largeMessageLength))

	hoster := gohost.NewHoster()
	hoster.GRPCAddr = grpcAddr
	hoster.RegisterGRPCEndpoint(func(s *grpc.Server) {
		pb.RegisterTestServiceServer(s, service)
	})

	hoster.MaxRecvMsgSize = math.MaxInt32

	// act - start the service
	go hoster.ListenAndServe()

	// make sure service has time to start
	time.Sleep(serviceStartDelay)

	// call the service at the gRPC endpoint
	conn, err := grpc.Dial(grpcAddr, grpc.WithInsecure())
	assert.NoError(t, err)
	client := pb.NewTestServiceClient(conn)
	grpcReq := pb.SendRequest{
		Value: largeValue,
	}
	grpcResp, err := client.Send(context.Background(), &grpcReq, grpc.MaxCallSendMsgSize(math.MaxInt32))

	// assert
	assert.NoError(t, err)
	assert.NotNil(t, grpcResp)
	assert.True(t, grpcResp.Success)
}

func Test_Hoster_ListenAndServe_GRPC_MaxRecvMsgSize_Fail(t *testing.T) {
	// arrange
	service := test.NewService()
	grpcAddr := getAddr(t)

	largeValue := string(make([]byte, largeMessageLength))

	hoster := gohost.NewHoster()
	hoster.GRPCAddr = grpcAddr
	hoster.RegisterGRPCEndpoint(func(s *grpc.Server) {
		pb.RegisterTestServiceServer(s, service)
	})

	hoster.MaxRecvMsgSize = 1

	// act - start the service
	go hoster.ListenAndServe()

	// make sure service has time to start
	time.Sleep(serviceStartDelay)

	// call the service at the gRPC endpoint
	conn, err := grpc.Dial(grpcAddr, grpc.WithInsecure())
	assert.NoError(t, err)
	client := pb.NewTestServiceClient(conn)
	grpcReq := pb.SendRequest{
		Value: largeValue,
	}
	grpcResp, err := client.Send(context.Background(), &grpcReq, grpc.MaxCallSendMsgSize(math.MaxInt32))

	// assert
	assert.Error(t, err)
	assert.Nil(t, grpcResp)
}

func Test_Hoster_ListenAndServe_GRPC_MaxSendMsgSize_Pass(t *testing.T) {
	// arrange
	service := test.NewService()
	grpcAddr := getAddr(t)

	hoster := gohost.NewHoster()
	hoster.GRPCAddr = grpcAddr
	hoster.RegisterGRPCEndpoint(func(s *grpc.Server) {
		pb.RegisterTestServiceServer(s, service)
	})

	hoster.MaxSendMsgSize = math.MaxInt32

	// act - start the service
	go hoster.ListenAndServe()

	// make sure service has time to start
	time.Sleep(serviceStartDelay)

	// call the service at the gRPC endpoint
	conn, err := grpc.Dial(grpcAddr, grpc.WithInsecure())
	assert.NoError(t, err)
	client := pb.NewTestServiceClient(conn)
	grpcReq := pb.LargeRequest{
		Length: largeMessageLength,
	}
	grpcResp, err := client.Large(context.Background(), &grpcReq, grpc.MaxCallRecvMsgSize(math.MaxInt32))

	// assert
	assert.NoError(t, err)
	assert.NotNil(t, grpcResp)
	assert.Equal(t, largeMessageLength, len(grpcResp.Echo))
}

func Test_Hoster_ListenAndServe_GRPC_MaxSendMsgSize_Fail(t *testing.T) {
	// arrange
	service := test.NewService()
	grpcAddr := getAddr(t)

	hoster := gohost.NewHoster()
	hoster.GRPCAddr = grpcAddr
	hoster.RegisterGRPCEndpoint(func(s *grpc.Server) {
		pb.RegisterTestServiceServer(s, service)
	})

	hoster.MaxSendMsgSize = 1

	// act - start the service
	go hoster.ListenAndServe()

	// make sure service has time to start
	time.Sleep(serviceStartDelay)

	// call the service at the gRPC endpoint
	conn, err := grpc.Dial(grpcAddr, grpc.WithInsecure())
	assert.NoError(t, err)
	client := pb.NewTestServiceClient(conn)
	grpcReq := pb.LargeRequest{
		Length: largeMessageLength,
	}
	grpcResp, err := client.Large(context.Background(), &grpcReq, grpc.MaxCallRecvMsgSize(math.MaxInt32))

	// assert
	assert.Error(t, err)
	assert.Nil(t, grpcResp)
}

func Test_Hoster_ListenAndServe_GRPC_UnaryInterceptor(t *testing.T) {
	// arrange
	service := test.NewService()
	grpcAddr := getAddr(t)

	expectedValue := "test"

	hoster := gohost.NewHoster()
	hoster.GRPCAddr = grpcAddr
	hoster.RegisterGRPCEndpoint(func(s *grpc.Server) {
		pb.RegisterTestServiceServer(s, service)
	})

	count := 1
	hoster.UnaryInterceptors = append(hoster.UnaryInterceptors, func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
		assert.Equal(t, 1, count)
		count++
		return handler(ctx, req)
	})
	hoster.UnaryInterceptors = append(hoster.UnaryInterceptors, func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
		assert.Equal(t, 2, count)
		count++
		return handler(ctx, req)
	})
	hoster.UnaryInterceptors = append(hoster.UnaryInterceptors, func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
		assert.Equal(t, 3, count)
		count++
		return handler(ctx, req)
	})

	// act - start the service
	go hoster.ListenAndServe()

	// make sure service has time to start
	time.Sleep(serviceStartDelay)

	// call the service at the gRPC endpoint
	conn, err := grpc.Dial(grpcAddr, grpc.WithInsecure())
	assert.NoError(t, err)
	client := pb.NewTestServiceClient(conn)
	grpcReq := pb.SendRequest{
		Value: expectedValue,
	}
	grpcResp, err := client.Echo(context.Background(), &grpcReq)

	// assert
	assert.NoError(t, err)
	assert.NotNil(t, grpcResp)
	assert.Equal(t, expectedValue, grpcResp.Echo)
}

func Test_Hoster_ListenAndServe_GRPC_StreamInterceptor(t *testing.T) {
	// arrange
	service := test.NewService()
	grpcAddr := getAddr(t)

	hoster := gohost.NewHoster()
	hoster.GRPCAddr = grpcAddr
	hoster.RegisterGRPCEndpoint(func(s *grpc.Server) {
		pb.RegisterTestServiceServer(s, service)
	})

	count := 1
	hoster.StreamInterceptors = append(hoster.StreamInterceptors, func(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
		assert.Equal(t, 1, count)
		count++
		return handler(srv, stream)
	})
	hoster.StreamInterceptors = append(hoster.StreamInterceptors, func(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
		assert.Equal(t, 2, count)
		count++
		return handler(srv, stream)
	})
	hoster.StreamInterceptors = append(hoster.StreamInterceptors, func(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
		assert.Equal(t, 3, count)
		count++
		return handler(srv, stream)
	})

	// act - start the service
	go hoster.ListenAndServe()

	// make sure service has time to start
	time.Sleep(serviceStartDelay)

	// call the service at the gRPC endpoint
	conn, err := grpc.Dial(grpcAddr, grpc.WithInsecure())
	assert.NoError(t, err)
	client := pb.NewTestServiceClient(conn)
	grpcResp, err := client.Stream(context.Background())
	assert.NoError(t, err)

	// send some values
	err = grpcResp.Send(&pb.SendRequest{
		Value: "value1",
	})
	assert.NoError(t, err)

	err = grpcResp.Send(&pb.SendRequest{
		Value: "value2",
	})
	assert.NoError(t, err)

	err = grpcResp.Send(&pb.SendRequest{
		Value: "value3",
	})
	assert.NoError(t, err)

	// close out the stream
	testResp, err := grpcResp.CloseAndRecv()

	// assert
	assert.NoError(t, err)
	assert.NotNil(t, testResp)
	assert.True(t, testResp.Success)
}

// func Test_ServeGRPC_EmptyGRPCAddress(t *testing.T) {
// 	// arrange
// 	service := test.NewService()

// 	// act
// 	err := ServeGRPC(service, "", nil)

// 	// assert
// 	assert.Error(t, err)
// }

// func Test_ServeGRPC_FailListen(t *testing.T) {
// 	// arrange
// 	service := test.NewService()
// 	grpcAddr := "badaddress"

// 	// act - start the service
// 	err := ServeGRPC(service, grpcAddr, nil)

// 	// assert
// 	assert.Error(t, err)
// }

// func Test_ServeGRPCWithTLS_NilService(t *testing.T) {
// 	// arrange
// 	grpcAddr := getAddr(t)
// 	certFile := "./testdata/test.crt"
// 	keyFile := "./testdata/test.key"

// 	// act
// 	err := ServeGRPCWithTLS(nil, grpcAddr, nil, certFile, keyFile)

// 	// assert
// 	assert.Error(t, err)
// }

// func Test_ServeGRPCWithTLS_EmptyGRPCAddress(t *testing.T) {
// 	// arrange
// 	service := test.NewService()
// 	certFile := "./testdata/test.crt"
// 	keyFile := "./testdata/test.key"

// 	// act
// 	err := ServeGRPCWithTLS(service, "", nil, certFile, keyFile)

// 	// assert
// 	assert.Error(t, err)
// }

// func Test_ServeGRPCWithTLS_EmptyCertFile(t *testing.T) {
// 	// arrange
// 	service := test.NewService()
// 	grpcAddr := getAddr(t)
// 	keyFile := "./testdata/test.key"

// 	// act
// 	err := ServeGRPCWithTLS(service, grpcAddr, nil, "", keyFile)

// 	// assert
// 	assert.Error(t, err)
// }

// func Test_ServeGRPCWithTLS_EmptyKeyFile(t *testing.T) {
// 	// arrange
// 	service := test.NewService()
// 	grpcAddr := getAddr(t)
// 	certFile := "./testdata/test.crt"

// 	// act
// 	err := ServeGRPCWithTLS(service, grpcAddr, nil, certFile, "")

// 	// assert
// 	assert.Error(t, err)
// }

// func Test_ServeGRPCWithTLS_BadCertFile(t *testing.T) {
// 	// arrange
// 	service := test.NewService()
// 	grpcAddr := getAddr(t)
// 	certFile := "./testdata/badcert.crt"
// 	keyFile := "./testdata/test.key"

// 	// act - start the service
// 	err := ServeGRPCWithTLS(service, grpcAddr, nil, certFile, keyFile)

// 	// assert
// 	assert.Error(t, err)
// }

// func Test_ServeGRPCWithTLS_FailListen(t *testing.T) {
// 	// arrange
// 	service := test.NewService()
// 	grpcAddr := "badaddress"
// 	certFile := "./testdata/test.crt"
// 	keyFile := "./testdata/test.key"

// 	// act - start the service
// 	err := ServeGRPCWithTLS(service, grpcAddr, nil, certFile, keyFile)

// 	// assert
// 	assert.Error(t, err)
// }
<commit_msg>Finished grpc tests.<commit_after>package test

import (
	"crypto/tls"
	"math"
	"testing"
	"time"

	"github.com/eleniums/gohost"
	"github.com/eleniums/gohost/examples/test"
	pb "github.com/eleniums/gohost/examples/test/proto"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"

	assert "github.com/stretchr/testify/require"
)

func Test_Hoster_ListenAndServe_GRPC_Successful(t *testing.T) {
	// arrange
	service := test.NewService()
	grpcAddr := getAddr(t)

	expectedValue := "test"

	hoster := gohost.NewHoster()
	hoster.GRPCAddr = grpcAddr
	hoster.RegisterGRPCEndpoint(func(s *grpc.Server) {
		pb.RegisterTestServiceServer(s, service)
	})

	// act - start the service
	go hoster.ListenAndServe()

	// make sure service has time to start
	time.Sleep(serviceStartDelay)

	// call the service at the gRPC endpoint
	conn, err := grpc.Dial(grpcAddr, grpc.WithInsecure())
	assert.NoError(t, err)
	client := pb.NewTestServiceClient(conn)
	grpcReq := pb.SendRequest{
		Value: expectedValue,
	}
	grpcResp, err := client.Echo(context.Background(), &grpcReq)

	// assert
	assert.NoError(t, err)
	assert.NotNil(t, grpcResp)
	assert.Equal(t, expectedValue, grpcResp.Echo)
}

func Test_Hoster_ListenAndServe_GRPC_WithTLS(t *testing.T) {
	// arrange
	service := test.NewService()
	grpcAddr := getAddr(t)

	expectedValue := "test"

	hoster := gohost.NewHoster()
	hoster.GRPCAddr = grpcAddr
	hoster.RegisterGRPCEndpoint(func(s *grpc.Server) {
		pb.RegisterTestServiceServer(s, service)
	})

	hoster.CertFile = "./testdata/test.crt"
	hoster.KeyFile = "./testdata/test.key"

	// act - start the service
	go hoster.ListenAndServe()

	// make sure service has time to start
	time.Sleep(serviceStartDelay)

	// call the service at the gRPC endpoint
	conn, err := grpc.Dial(grpcAddr, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{InsecureSkipVerify: true})))
	assert.NoError(t, err)
	client := pb.NewTestServiceClient(conn)
	grpcReq := pb.SendRequest{
		Value: expectedValue,
	}
	grpcResp, err := client.Echo(context.Background(), &grpcReq)

	// assert
	assert.NoError(t, err)
	assert.NotNil(t, grpcResp)
	assert.Equal(t, expectedValue, grpcResp.Echo)
}

func Test_Hoster_ListenAndServe_GRPC_EmptyAddress(t *testing.T) {
	// arrange
	service := test.NewService()

	hoster := gohost.NewHoster()
	hoster.GRPCAddr = ""
	hoster.RegisterGRPCEndpoint(func(s *grpc.Server) {
		pb.RegisterTestServiceServer(s, service)
	})

	// act - start the service
	err := hoster.ListenAndServe()

	// assert
	assert.Error(t, err)
}

func Test_Hoster_ListenAndServe_GRPC_InvalidAddress(t *testing.T) {
	// arrange
	service := test.NewService()

	hoster := gohost.NewHoster()
	hoster.GRPCAddr = "badaddress"
	hoster.RegisterGRPCEndpoint(func(s *grpc.Server) {
		pb.RegisterTestServiceServer(s, service)
	})

	// act - start the service
	err := hoster.ListenAndServe()

	// assert
	assert.Error(t, err)
}

func Test_Hoster_ListenAndServe_GRPC_InvalidCertFile(t *testing.T) {
	// arrange
	service := test.NewService()
	grpcAddr := getAddr(t)

	hoster := gohost.NewHoster()
	hoster.GRPCAddr = grpcAddr
	hoster.RegisterGRPCEndpoint(func(s *grpc.Server) {
		pb.RegisterTestServiceServer(s, service)
	})

	hoster.CertFile = "./testdata/badcert.crt"
	hoster.KeyFile = "./testdata/test.key"

	// act - start the service
	err := hoster.ListenAndServe()

	// assert
	assert.Error(t, err)
}

func Test_Hoster_ListenAndServe_GRPC_InvalidKeyFile(t *testing.T) {
	// arrange
	service := test.NewService()
	grpcAddr := getAddr(t)

	hoster := gohost.NewHoster()
	hoster.GRPCAddr = grpcAddr
	hoster.RegisterGRPCEndpoint(func(s *grpc.Server) {
		pb.RegisterTestServiceServer(s, service)
	})

	hoster.CertFile = "./testdata/test.crt"
	hoster.KeyFile = "./testdata/badkey.key"

	// act - start the service
	err := hoster.ListenAndServe()

	// assert
	assert.Error(t, err)
}

func Test_Hoster_ListenAndServe_GRPC_MaxRecvMsgSize_Pass(t *testing.T) {
	// arrange
	service := test.NewService()
	grpcAddr := getAddr(t)

	largeValue := string(make([]byte, largeMessageLength))

	hoster := gohost.NewHoster()
	hoster.GRPCAddr = grpcAddr
	hoster.RegisterGRPCEndpoint(func(s *grpc.Server) {
		pb.RegisterTestServiceServer(s, service)
	})

	hoster.MaxRecvMsgSize = math.MaxInt32

	// act - start the service
	go hoster.ListenAndServe()

	// make sure service has time to start
	time.Sleep(serviceStartDelay)

	// call the service at the gRPC endpoint
	conn, err := grpc.Dial(grpcAddr, grpc.WithInsecure())
	assert.NoError(t, err)
	client := pb.NewTestServiceClient(conn)
	grpcReq := pb.SendRequest{
		Value: largeValue,
	}
	grpcResp, err := client.Send(context.Background(), &grpcReq, grpc.MaxCallSendMsgSize(math.MaxInt32))

	// assert
	assert.NoError(t, err)
	assert.NotNil(t, grpcResp)
	assert.True(t, grpcResp.Success)
}

func Test_Hoster_ListenAndServe_GRPC_MaxRecvMsgSize_Fail(t *testing.T) {
	// arrange
	service := test.NewService()
	grpcAddr := getAddr(t)

	largeValue := string(make([]byte, largeMessageLength))

	hoster := gohost.NewHoster()
	hoster.GRPCAddr = grpcAddr
	hoster.RegisterGRPCEndpoint(func(s *grpc.Server) {
		pb.RegisterTestServiceServer(s, service)
	})

	hoster.MaxRecvMsgSize = 1

	// act - start the service
	go hoster.ListenAndServe()

	// make sure service has time to start
	time.Sleep(serviceStartDelay)

	// call the service at the gRPC endpoint
	conn, err := grpc.Dial(grpcAddr, grpc.WithInsecure())
	assert.NoError(t, err)
	client := pb.NewTestServiceClient(conn)
	grpcReq := pb.SendRequest{
		Value: largeValue,
	}
	grpcResp, err := client.Send(context.Background(), &grpcReq, grpc.MaxCallSendMsgSize(math.MaxInt32))

	// assert
	assert.Error(t, err)
	assert.Nil(t, grpcResp)
}

func Test_Hoster_ListenAndServe_GRPC_MaxSendMsgSize_Pass(t *testing.T) {
	// arrange
	service := test.NewService()
	grpcAddr := getAddr(t)

	hoster := gohost.NewHoster()
	hoster.GRPCAddr = grpcAddr
	hoster.RegisterGRPCEndpoint(func(s *grpc.Server) {
		pb.RegisterTestServiceServer(s, service)
	})

	hoster.MaxSendMsgSize = math.MaxInt32

	// act - start the service
	go hoster.ListenAndServe()

	// make sure service has time to start
	time.Sleep(serviceStartDelay)

	// call the service at the gRPC endpoint
	conn, err := grpc.Dial(grpcAddr, grpc.WithInsecure())
	assert.NoError(t, err)
	client := pb.NewTestServiceClient(conn)
	grpcReq := pb.LargeRequest{
		Length: largeMessageLength,
	}
	grpcResp, err := client.Large(context.Background(), &grpcReq, grpc.MaxCallRecvMsgSize(math.MaxInt32))

	// assert
	assert.NoError(t, err)
	assert.NotNil(t, grpcResp)
	assert.Equal(t, largeMessageLength, len(grpcResp.Echo))
}

func Test_Hoster_ListenAndServe_GRPC_MaxSendMsgSize_Fail(t *testing.T) {
	// arrange
	service := test.NewService()
	grpcAddr := getAddr(t)

	hoster := gohost.NewHoster()
	hoster.GRPCAddr = grpcAddr
	hoster.RegisterGRPCEndpoint(func(s *grpc.Server) {
		pb.RegisterTestServiceServer(s, service)
	})

	hoster.MaxSendMsgSize = 1

	// act - start the service
	go hoster.ListenAndServe()

	// make sure service has time to start
	time.Sleep(serviceStartDelay)

	// call the service at the gRPC endpoint
	conn, err := grpc.Dial(grpcAddr, grpc.WithInsecure())
	assert.NoError(t, err)
	client := pb.NewTestServiceClient(conn)
	grpcReq := pb.LargeRequest{
		Length: largeMessageLength,
	}
	grpcResp, err := client.Large(context.Background(), &grpcReq, grpc.MaxCallRecvMsgSize(math.MaxInt32))

	// assert
	assert.Error(t, err)
	assert.Nil(t, grpcResp)
}

func Test_Hoster_ListenAndServe_GRPC_UnaryInterceptor(t *testing.T) {
	// arrange
	service := test.NewService()
	grpcAddr := getAddr(t)

	expectedValue := "test"

	hoster := gohost.NewHoster()
	hoster.GRPCAddr = grpcAddr
	hoster.RegisterGRPCEndpoint(func(s *grpc.Server) {
		pb.RegisterTestServiceServer(s, service)
	})

	count := 1
	hoster.UnaryInterceptors = append(hoster.UnaryInterceptors, func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
		assert.Equal(t, 1, count)
		count++
		return handler(ctx, req)
	})
	hoster.UnaryInterceptors = append(hoster.UnaryInterceptors, func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
		assert.Equal(t, 2, count)
		count++
		return handler(ctx, req)
	})
	hoster.UnaryInterceptors = append(hoster.UnaryInterceptors, func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
		assert.Equal(t, 3, count)
		count++
		return handler(ctx, req)
	})

	// act - start the service
	go hoster.ListenAndServe()

	// make sure service has time to start
	time.Sleep(serviceStartDelay)

	// call the service at the gRPC endpoint
	conn, err := grpc.Dial(grpcAddr, grpc.WithInsecure())
	assert.NoError(t, err)
	client := pb.NewTestServiceClient(conn)
	grpcReq := pb.SendRequest{
		Value: expectedValue,
	}
	grpcResp, err := client.Echo(context.Background(), &grpcReq)

	// assert
	assert.NoError(t, err)
	assert.NotNil(t, grpcResp)
	assert.Equal(t, expectedValue, grpcResp.Echo)
}

func Test_Hoster_ListenAndServe_GRPC_StreamInterceptor(t *testing.T) {
	// arrange
	service := test.NewService()
	grpcAddr := getAddr(t)

	hoster := gohost.NewHoster()
	hoster.GRPCAddr = grpcAddr
	hoster.RegisterGRPCEndpoint(func(s *grpc.Server) {
		pb.RegisterTestServiceServer(s, service)
	})

	count := 1
	hoster.StreamInterceptors = append(hoster.StreamInterceptors, func(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
		assert.Equal(t, 1, count)
		count++
		return handler(srv, stream)
	})
	hoster.StreamInterceptors = append(hoster.StreamInterceptors, func(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
		assert.Equal(t, 2, count)
		count++
		return handler(srv, stream)
	})
	hoster.StreamInterceptors = append(hoster.StreamInterceptors, func(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
		assert.Equal(t, 3, count)
		count++
		return handler(srv, stream)
	})

	// act - start the service
	go hoster.ListenAndServe()

	// make sure service has time to start
	time.Sleep(serviceStartDelay)

	// call the service at the gRPC endpoint
	conn, err := grpc.Dial(grpcAddr, grpc.WithInsecure())
	assert.NoError(t, err)
	client := pb.NewTestServiceClient(conn)
	grpcResp, err := client.Stream(context.Background())
	assert.NoError(t, err)

	// send some values
	err = grpcResp.Send(&pb.SendRequest{
		Value: "value1",
	})
	assert.NoError(t, err)

	err = grpcResp.Send(&pb.SendRequest{
		Value: "value2",
	})
	assert.NoError(t, err)

	err = grpcResp.Send(&pb.SendRequest{
		Value: "value3",
	})
	assert.NoError(t, err)

	// close out the stream
	testResp, err := grpcResp.CloseAndRecv()

	// assert
	assert.NoError(t, err)
	assert.NotNil(t, testResp)
	assert.True(t, testResp.Success)
}
<|endoftext|>


<commit_before>// Copyright 2017 CoreOS, Inc.
//
// 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 blackbox

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"testing"
	"time"

	"github.com/pin/tftp"

	"github.com/coreos/ignition/tests/register"
	"github.com/coreos/ignition/tests/types"

	// Register the tests
	_ "github.com/coreos/ignition/tests/registry"
)

// HTTP Server
func (server *HTTPServer) Config(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte(`{
	"ignition": { "version": "2.0.0" },
	"storage": {
		"files": [{
		  "filesystem": "root",
		  "path": "/foo/bar",
		  "contents": { "source": "data:,example%20file%0A" }
		}]
	}
}`))
}

func (server *HTTPServer) Contents(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte(`asdf
fdsa`))
}

type HTTPServer struct{}

func (server *HTTPServer) Start() {
	http.HandleFunc("/contents", server.Contents)
	http.HandleFunc("/config", server.Config)

	s := &http.Server{Addr: ":8080"}
	go s.ListenAndServe()
}

// TFTP Server
func (server *TFTPServer) ReadHandler(filename string, rf io.ReaderFrom) error {
	var buf *bytes.Reader
	if strings.Contains(filename, "contents") {
		buf = bytes.NewReader([]byte(`asdf
fdsa`))
	} else if strings.Contains(filename, "config") {
		buf = bytes.NewReader([]byte(`{
        "ignition": { "version": "2.0.0" },
        "storage": {
                "files": [{
                  "filesystem": "root",
                  "path": "/foo/bar",
                  "contents": { "source": "data:,example%20file%0A" }
                }]
        }
}`))
	}

	_, err := rf.ReadFrom(buf)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v\n", err)
		return err
	}
	return nil
}

type TFTPServer struct{}

func (server *TFTPServer) Start() {
	s := tftp.NewServer(server.ReadHandler, nil)
	s.SetTimeout(5 * time.Second)
	go s.ListenAndServe(":69")
}

func TestMain(m *testing.M) {
	httpServer := &HTTPServer{}
	httpServer.Start()
	tftpServer := &TFTPServer{}
	tftpServer.Start()

	os.Exit(m.Run())
}

func TestIgnitionBlackBox(t *testing.T) {
	for _, test := range register.Tests[register.PositiveTest] {
		t.Run(test.Name, func(t *testing.T) {
			outer(t, test, false)
		})
	}
}

func TestIgnitionBlackBoxNegative(t *testing.T) {
	for _, test := range register.Tests[register.NegativeTest] {
		t.Run(test.Name, func(t *testing.T) {
			outer(t, test, true)
		})
	}
}

func outer(t *testing.T, test types.Test, negativeTests bool) {
	t.Log(test.Name)

	if os.Getenv("TMPDIR") == "" {
		originalTmpDir := os.Getenv("TMPDIR")
		tmpDirectory, err := ioutil.TempDir("/var/tmp", "")
		if err != nil {
			t.Fatalf("failed to create a temp dir: %v", err)
		}
		// the tmpDirectory must be 0755 or the tests will fail as the tool will
		// not have permissions to perform some actions in the mounted folders
		err = os.Chmod(tmpDirectory, 0755)
		if err != nil {
			t.Fatalf("failed to change mode of temp dir: %v", err)
		}
		err = os.Setenv("TMPDIR", tmpDirectory)
		if err != nil {
			t.Fatalf("failed to set TMPDIR environment var: %v", err)
		}
		defer os.Setenv("TMPDIR", originalTmpDir)
		defer os.RemoveAll(tmpDirectory)
	}

	var rootLocation string

	// Setup
	for i, disk := range test.In {
		// Move the ImageFile inside the temp dir
		imageFileName := disk.ImageFile // create a copy for doing device replaces later
		disk.ImageFile = filepath.Join(os.Getenv("TMPDIR"), disk.ImageFile)
		test.Out[i].ImageFile = filepath.Join(os.Getenv("TMPDIR"), test.Out[i].ImageFile)

		// There may be more partitions created by Ignition, so look at the
		// expected output instead of the input to determine image size
		imageSize := calculateImageSize(test.Out[i].Partitions)

		// Finish data setup
		for _, part := range disk.Partitions {
			if part.GUID == "" {
				part.GUID = generateUUID(t)
			}
			updateTypeGUID(t, part)
		}
		setOffsets(disk.Partitions)
		for _, part := range test.Out[i].Partitions {
			updateTypeGUID(t, part)
		}
		setOffsets(test.Out[i].Partitions)

		// Creation
		createVolume(t, disk.ImageFile, imageSize, 20, 16, 63, disk.Partitions)
		loopDevice := setDevices(t, disk.ImageFile, disk.Partitions)
		rootMounted := mountRootPartition(t, disk.Partitions)
		if rootMounted && strings.Contains(test.Config, "passwd") {
			prepareRootPartitionForPasswd(t, disk.Partitions)
		}
		mountPartitions(t, disk.Partitions)
		createFiles(t, disk.Partitions)
		unmountPartitions(t, disk.Partitions)

		// Mount device name substitution
		for _, d := range test.MntDevices {
			device := pickDevice(t, disk.Partitions, disk.ImageFile, d.Label)
			// The device may not be on this disk, if it's not found here let's
			// assume we'll find it on another one and keep going
			if device != "" {
				test.Config = strings.Replace(test.Config, d.Substitution, device, -1)
			}
		}

		// Replace any instance of $<image-file> with the actual loop device
		// that got assigned to it
		test.Config = strings.Replace(test.Config, "$"+imageFileName, loopDevice, -1)

		if rootLocation == "" {
			rootLocation = getRootLocation(disk.Partitions)
		}
	}

	// Validation and cleanup deferral
	for i, disk := range test.Out {
		// Update out structure with mount points & devices
		setExpectedPartitionsDrive(test.In[i].Partitions, disk.Partitions)

		// Cleanup
		defer removeFile(t, disk.ImageFile)
		defer removeMountFolders(t, disk.Partitions)
		defer destroyDevices(t, disk.ImageFile, disk.Partitions)
		defer unmountRootPartition(t, disk.Partitions)
	}

	if rootLocation == "" {
		t.Fatal("ROOT filesystem not found! A partition labeled ROOT is requred")
	}

	// Let's make sure that all of the devices we needed to substitute names in
	// for were found
	for _, d := range test.MntDevices {
		if strings.Contains(test.Config, d.Substitution) {
			t.Fatalf("Didn't find a drive with label: %s", d.Substitution)
		}
	}

	// Ignition
	configDir := writeIgnitionConfig(t, test.Config)
	defer removeFile(t, filepath.Join(configDir, "config.ign"))
	disks := runIgnition(t, "disks", rootLocation, configDir, negativeTests)
	files := runIgnition(t, "files", rootLocation, configDir, negativeTests)
	if negativeTests && disks && files {
		t.Fatal("Expected failure and ignition succeeded")
	}

	for _, disk := range test.Out {
		if !negativeTests {
			// Validation
			mountPartitions(t, disk.Partitions)
			t.Log(disk.ImageFile)
			validatePartitions(t, disk.Partitions, disk.ImageFile)
			validateFilesystems(t, disk.Partitions, disk.ImageFile)
			validateFilesDirectoriesAndLinks(t, disk.Partitions)
			unmountPartitions(t, disk.Partitions)
		}
	}
}
<commit_msg>tests: prefix tempdir names to denote their origin<commit_after>// Copyright 2017 CoreOS, Inc.
//
// 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 blackbox

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"testing"
	"time"

	"github.com/pin/tftp"

	"github.com/coreos/ignition/tests/register"
	"github.com/coreos/ignition/tests/types"

	// Register the tests
	_ "github.com/coreos/ignition/tests/registry"
)

// HTTP Server
func (server *HTTPServer) Config(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte(`{
	"ignition": { "version": "2.0.0" },
	"storage": {
		"files": [{
		  "filesystem": "root",
		  "path": "/foo/bar",
		  "contents": { "source": "data:,example%20file%0A" }
		}]
	}
}`))
}

func (server *HTTPServer) Contents(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte(`asdf
fdsa`))
}

type HTTPServer struct{}

func (server *HTTPServer) Start() {
	http.HandleFunc("/contents", server.Contents)
	http.HandleFunc("/config", server.Config)

	s := &http.Server{Addr: ":8080"}
	go s.ListenAndServe()
}

// TFTP Server
func (server *TFTPServer) ReadHandler(filename string, rf io.ReaderFrom) error {
	var buf *bytes.Reader
	if strings.Contains(filename, "contents") {
		buf = bytes.NewReader([]byte(`asdf
fdsa`))
	} else if strings.Contains(filename, "config") {
		buf = bytes.NewReader([]byte(`{
        "ignition": { "version": "2.0.0" },
        "storage": {
                "files": [{
                  "filesystem": "root",
                  "path": "/foo/bar",
                  "contents": { "source": "data:,example%20file%0A" }
                }]
        }
}`))
	}

	_, err := rf.ReadFrom(buf)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v\n", err)
		return err
	}
	return nil
}

type TFTPServer struct{}

func (server *TFTPServer) Start() {
	s := tftp.NewServer(server.ReadHandler, nil)
	s.SetTimeout(5 * time.Second)
	go s.ListenAndServe(":69")
}

func TestMain(m *testing.M) {
	httpServer := &HTTPServer{}
	httpServer.Start()
	tftpServer := &TFTPServer{}
	tftpServer.Start()

	os.Exit(m.Run())
}

func TestIgnitionBlackBox(t *testing.T) {
	for _, test := range register.Tests[register.PositiveTest] {
		t.Run(test.Name, func(t *testing.T) {
			outer(t, test, false)
		})
	}
}

func TestIgnitionBlackBoxNegative(t *testing.T) {
	for _, test := range register.Tests[register.NegativeTest] {
		t.Run(test.Name, func(t *testing.T) {
			outer(t, test, true)
		})
	}
}

func outer(t *testing.T, test types.Test, negativeTests bool) {
	t.Log(test.Name)

	if os.Getenv("TMPDIR") == "" {
		originalTmpDir := os.Getenv("TMPDIR")
		tmpDirectory, err := ioutil.TempDir("/var/tmp", "ignition-blackbox-")
		if err != nil {
			t.Fatalf("failed to create a temp dir: %v", err)
		}
		// the tmpDirectory must be 0755 or the tests will fail as the tool will
		// not have permissions to perform some actions in the mounted folders
		err = os.Chmod(tmpDirectory, 0755)
		if err != nil {
			t.Fatalf("failed to change mode of temp dir: %v", err)
		}
		err = os.Setenv("TMPDIR", tmpDirectory)
		if err != nil {
			t.Fatalf("failed to set TMPDIR environment var: %v", err)
		}
		defer os.Setenv("TMPDIR", originalTmpDir)
		defer os.RemoveAll(tmpDirectory)
	}

	var rootLocation string

	// Setup
	for i, disk := range test.In {
		// Move the ImageFile inside the temp dir
		imageFileName := disk.ImageFile // create a copy for doing device replaces later
		disk.ImageFile = filepath.Join(os.Getenv("TMPDIR"), disk.ImageFile)
		test.Out[i].ImageFile = filepath.Join(os.Getenv("TMPDIR"), test.Out[i].ImageFile)

		// There may be more partitions created by Ignition, so look at the
		// expected output instead of the input to determine image size
		imageSize := calculateImageSize(test.Out[i].Partitions)

		// Finish data setup
		for _, part := range disk.Partitions {
			if part.GUID == "" {
				part.GUID = generateUUID(t)
			}
			updateTypeGUID(t, part)
		}
		setOffsets(disk.Partitions)
		for _, part := range test.Out[i].Partitions {
			updateTypeGUID(t, part)
		}
		setOffsets(test.Out[i].Partitions)

		// Creation
		createVolume(t, disk.ImageFile, imageSize, 20, 16, 63, disk.Partitions)
		loopDevice := setDevices(t, disk.ImageFile, disk.Partitions)
		rootMounted := mountRootPartition(t, disk.Partitions)
		if rootMounted && strings.Contains(test.Config, "passwd") {
			prepareRootPartitionForPasswd(t, disk.Partitions)
		}
		mountPartitions(t, disk.Partitions)
		createFiles(t, disk.Partitions)
		unmountPartitions(t, disk.Partitions)

		// Mount device name substitution
		for _, d := range test.MntDevices {
			device := pickDevice(t, disk.Partitions, disk.ImageFile, d.Label)
			// The device may not be on this disk, if it's not found here let's
			// assume we'll find it on another one and keep going
			if device != "" {
				test.Config = strings.Replace(test.Config, d.Substitution, device, -1)
			}
		}

		// Replace any instance of $<image-file> with the actual loop device
		// that got assigned to it
		test.Config = strings.Replace(test.Config, "$"+imageFileName, loopDevice, -1)

		if rootLocation == "" {
			rootLocation = getRootLocation(disk.Partitions)
		}
	}

	// Validation and cleanup deferral
	for i, disk := range test.Out {
		// Update out structure with mount points & devices
		setExpectedPartitionsDrive(test.In[i].Partitions, disk.Partitions)

		// Cleanup
		defer removeFile(t, disk.ImageFile)
		defer removeMountFolders(t, disk.Partitions)
		defer destroyDevices(t, disk.ImageFile, disk.Partitions)
		defer unmountRootPartition(t, disk.Partitions)
	}

	if rootLocation == "" {
		t.Fatal("ROOT filesystem not found! A partition labeled ROOT is requred")
	}

	// Let's make sure that all of the devices we needed to substitute names in
	// for were found
	for _, d := range test.MntDevices {
		if strings.Contains(test.Config, d.Substitution) {
			t.Fatalf("Didn't find a drive with label: %s", d.Substitution)
		}
	}

	// Ignition
	configDir := writeIgnitionConfig(t, test.Config)
	defer removeFile(t, filepath.Join(configDir, "config.ign"))
	disks := runIgnition(t, "disks", rootLocation, configDir, negativeTests)
	files := runIgnition(t, "files", rootLocation, configDir, negativeTests)
	if negativeTests && disks && files {
		t.Fatal("Expected failure and ignition succeeded")
	}

	for _, disk := range test.Out {
		if !negativeTests {
			// Validation
			mountPartitions(t, disk.Partitions)
			t.Log(disk.ImageFile)
			validatePartitions(t, disk.Partitions, disk.ImageFile)
			validateFilesystems(t, disk.Partitions, disk.ImageFile)
			validateFilesDirectoriesAndLinks(t, disk.Partitions)
			unmountPartitions(t, disk.Partitions)
		}
	}
}
<|endoftext|>