<commit_before>package service

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

	"github.com/onsi/ginkgo"

	"github.com/openshift/origin/pkg/monitor"
	"github.com/openshift/origin/test/extended/util/disruption"
	v1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/client-go/kubernetes/scheme"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/events"
	"k8s.io/kubernetes/test/e2e/framework"
	e2enetwork "k8s.io/kubernetes/test/e2e/framework/network"
	"k8s.io/kubernetes/test/e2e/framework/service"
	"k8s.io/kubernetes/test/e2e/upgrades"
)

// 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 "[sig-network-edge] 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
		s.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyTypeLocal
		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 := 10 * time.Minute
	// require thirty seconds of passing requests to continue (in case the SLB becomes available and then degrades)
	TestReachableHTTPWithMinSuccessCount(tcpIngressIP, svcPort, 30, 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.EventsV1()})
	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(ctx)
			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(ctx)
			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)
}

// TestReachableHTTPWithMinSuccessCount tests that the given host serves HTTP on the given port for a minimum of successCount number of
// counts at a given interval. If the service reachability fails, the counter gets reset
func TestReachableHTTPWithMinSuccessCount(host string, port int, successCount int, timeout time.Duration) {
	consecutiveSuccessCnt := 0
	err := wait.PollImmediate(framework.Poll, timeout, func() (bool, error) {
		result := e2enetwork.PokeHTTP(host, port, "/echo?msg=hello",
			&e2enetwork.HTTPPokeParams{
				BodyContains:   "hello",
				RetriableCodes: []int{},
			})
		if result.Status == e2enetwork.HTTPSuccess {
			consecutiveSuccessCnt++
			return consecutiveSuccessCnt >= successCount, nil
		}
		consecutiveSuccessCnt = 0
		return false, nil // caller can retry
	})
	framework.ExpectNoError(err)
}
<commit_msg>skip service type load balancer upgrade test on ovirt<commit_after>package service

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

	"github.com/onsi/ginkgo"
	configv1 "github.com/openshift/api/config/v1"
	configclient "github.com/openshift/client-go/config/clientset/versioned"
	"github.com/openshift/origin/pkg/monitor"
	"github.com/openshift/origin/test/extended/util/disruption"
	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/client-go/kubernetes/scheme"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/events"
	"k8s.io/kubernetes/test/e2e/framework"
	e2enetwork "k8s.io/kubernetes/test/e2e/framework/network"
	"k8s.io/kubernetes/test/e2e/framework/service"
	"k8s.io/kubernetes/test/e2e/upgrades"
)

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

	unsupportedPlatform bool
}

func (UpgradeTest) Name() string { return "k8s-service-lb-available" }
func (UpgradeTest) DisplayName() string {
	return "[sig-network-edge] 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) {
	configClient, err := configclient.NewForConfig(f.ClientConfig())
	framework.ExpectNoError(err)
	infra, err := configClient.ConfigV1().Infrastructures().Get(context.Background(), "cluster", metav1.GetOptions{})
	framework.ExpectNoError(err)
	// ovirt does not support service type loadbalancer because it doesn't program a cloud.
	if infra.Status.PlatformStatus.Type == configv1.OvirtPlatformType {
		t.unsupportedPlatform = true
	}
	if t.unsupportedPlatform {
		return
	}

	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
		s.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyTypeLocal
		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 := 10 * time.Minute
	// require thirty seconds of passing requests to continue (in case the SLB becomes available and then degrades)
	TestReachableHTTPWithMinSuccessCount(tcpIngressIP, svcPort, 30, 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) {
	if t.unsupportedPlatform {
		return
	}

	client, err := framework.LoadClientset()
	framework.ExpectNoError(err)

	stopCh := make(chan struct{})
	defer close(stopCh)
	newBroadcaster := events.NewBroadcaster(&events.EventSinkImpl{Interface: client.EventsV1()})
	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(ctx)
			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(ctx)
			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)
}

// TestReachableHTTPWithMinSuccessCount tests that the given host serves HTTP on the given port for a minimum of successCount number of
// counts at a given interval. If the service reachability fails, the counter gets reset
func TestReachableHTTPWithMinSuccessCount(host string, port int, successCount int, timeout time.Duration) {
	consecutiveSuccessCnt := 0
	err := wait.PollImmediate(framework.Poll, timeout, func() (bool, error) {
		result := e2enetwork.PokeHTTP(host, port, "/echo?msg=hello",
			&e2enetwork.HTTPPokeParams{
				BodyContains:   "hello",
				RetriableCodes: []int{},
			})
		if result.Status == e2enetwork.HTTPSuccess {
			consecutiveSuccessCnt++
			return consecutiveSuccessCnt >= successCount, nil
		}
		consecutiveSuccessCnt = 0
		return false, nil // caller can retry
	})
	framework.ExpectNoError(err)
}
<|endoftext|>


<commit_before>package main

import (
	"socialapi/models"
	"socialapi/rest"
	"testing"

	. "github.com/smartystreets/goconvey/convey"
)

func TestChannelCreation(t *testing.T) {
	Convey("while  testing channel", t, func() {
		Convey("First Create Users", func() {
			account1 := models.NewAccount()
			account1.OldId = AccountOldId.Hex()
			account, err := rest.CreateAccount(account1)
			So(err, ShouldBeNil)
			So(account, ShouldNotBeNil)

			nonOwnerAccount := models.NewAccount()
			nonOwnerAccount.OldId = AccountOldId2.Hex()
			nonOwnerAccount, err = rest.CreateAccount(nonOwnerAccount)
			So(err, ShouldBeNil)
			So(nonOwnerAccount, ShouldNotBeNil)

			Convey("we should be able to create it", func() {
				channel1, err := rest.CreateChannelByGroupNameAndType(account1.Id, "testgroup", models.Channel_TYPE_CHAT)
				So(err, ShouldBeNil)
				So(channel1, ShouldNotBeNil)

				Convey("owner should be able to update it", func() {
					updatedPurpose := "another purpose from the paradise"
					channel1.Purpose = updatedPurpose

					channel2, err := rest.UpdateChannel(channel1)
					So(err, ShouldBeNil)
					So(channel2, ShouldNotBeNil)

					So(channel1.Purpose, ShouldEqual, channel1.Purpose)
				})
				Convey("non-owner should not be able to update it", func() {
					updatedPurpose := "another purpose from the paradise"
					channel1.Purpose = updatedPurpose
					channel1.CreatorId = nonOwnerAccount.Id

					channel2, err := rest.UpdateChannel(channel1)
					So(err, ShouldNotBeNil)
					So(channel2, ShouldBeNil)
				})
			})

			Convey("owner should be able to add new participants into it", func() {
				channel1, err := rest.CreateChannelByGroupNameAndType(account1.Id, "testgroup", models.Channel_TYPE_CHAT)
				So(err, ShouldBeNil)
				So(channel1, ShouldNotBeNil)

				channelParticipant, err := rest.AddChannelParticipant(channel1.Id, account1.Id, nonOwnerAccount.Id)
				// there should be an err
				So(err, ShouldBeNil)
				// channel should be nil
				So(channelParticipant, ShouldNotBeNil)
			})

			Convey("normal user shouldnt be able to add new participants to it", func() {
				channel1, err := rest.CreateChannelByGroupNameAndType(account1.Id, "testgroup", models.Channel_TYPE_CHAT)
				So(err, ShouldBeNil)
				So(channel1, ShouldNotBeNil)

				channelParticipant, err := rest.AddChannelParticipant(channel1.Id, nonOwnerAccount.Id, nonOwnerAccount.Id)
				// there should be an err
				So(err, ShouldNotBeNil)
				// channel should be nil
				So(channelParticipant, ShouldBeNil)
			})

			Convey("owner should be able to remove participants from it", func() {
				channel1, err := rest.CreateChannelByGroupNameAndType(account1.Id, "testgroup", models.Channel_TYPE_CHAT)
				So(err, ShouldBeNil)
				So(channel1, ShouldNotBeNil)

				channelParticipant, err := rest.AddChannelParticipant(channel1.Id, account1.Id, nonOwnerAccount.Id)
				// there should be an err
				So(err, ShouldBeNil)
				// channel should be nil
				So(channelParticipant, ShouldNotBeNil)

				_, err = rest.DeleteChannelParticipant(channel1.Id, account1.Id, nonOwnerAccount.Id)
				// there should be an err
				So(err, ShouldBeNil)
			})

			Convey("normal user shouldnt be able to remove participants from it", func() {
				channel1, err := rest.CreateChannelByGroupNameAndType(account1.Id, "testgroup", models.Channel_TYPE_CHAT)
				So(err, ShouldBeNil)
				So(channel1, ShouldNotBeNil)

				channelParticipant, err := rest.AddChannelParticipant(channel1.Id, account1.Id, nonOwnerAccount.Id)
				// there should be an err
				So(err, ShouldBeNil)
				// channel should be nil
				So(channelParticipant, ShouldNotBeNil)

				_, err = rest.DeleteChannelParticipant(channel1.Id, nonOwnerAccount.Id, nonOwnerAccount.Id)
				// there should be an err
				So(err, ShouldNotBeNil)
			})

			Convey("owner should be able list participants", func() {
				channel1, err := rest.CreateChannelByGroupNameAndType(account1.Id, "testgroup", models.Channel_TYPE_CHAT)
				So(err, ShouldBeNil)
				So(channel1, ShouldNotBeNil)

				// add first participant
				channelParticipant1, err := rest.AddChannelParticipant(channel1.Id, account1.Id, nonOwnerAccount.Id)
				// there should be an err
				So(err, ShouldBeNil)
				// channel should be nil
				So(channelParticipant1, ShouldNotBeNil)

				nonOwnerAccount2 := models.NewAccount()
				nonOwnerAccount2.OldId = AccountOldId3.Hex()
				nonOwnerAccount2, err = rest.CreateAccount(nonOwnerAccount2)
				So(err, ShouldBeNil)
				So(nonOwnerAccount2, ShouldNotBeNil)

				channelParticipant2, err := rest.AddChannelParticipant(channel1.Id, account1.Id, nonOwnerAccount2.Id)
				// there should be an err
				So(err, ShouldBeNil)
				// channel should be nil
				So(channelParticipant2, ShouldNotBeNil)

				participants, err := rest.ListChannelParticipants(channel1.Id, account1.Id)
				// there should be an err
				So(err, ShouldBeNil)
				So(participants, ShouldNotBeNil)
				So(len(participants), ShouldEqual, 2)

			})

			Convey("normal user should be able to list participants", func() {
				channel1, err := rest.CreateChannelByGroupNameAndType(account1.Id, "testgroup", models.Channel_TYPE_CHAT)
				So(err, ShouldBeNil)
				So(channel1, ShouldNotBeNil)

				// add first participant
				channelParticipant1, err := rest.AddChannelParticipant(channel1.Id, account1.Id, nonOwnerAccount.Id)
				// there should be an err
				So(err, ShouldBeNil)
				// channel should be nil
				So(channelParticipant1, ShouldNotBeNil)

				nonOwnerAccount2 := models.NewAccount()
				nonOwnerAccount2.OldId = AccountOldId3.Hex()
				nonOwnerAccount2, err = rest.CreateAccount(nonOwnerAccount2)
				So(err, ShouldBeNil)
				So(nonOwnerAccount2, ShouldNotBeNil)

				channelParticipant2, err := rest.AddChannelParticipant(channel1.Id, account1.Id, nonOwnerAccount2.Id)
				// there should be an err
				So(err, ShouldBeNil)
				// channel should be nil
				So(channelParticipant2, ShouldNotBeNil)

				participants, err := rest.ListChannelParticipants(channel1.Id, nonOwnerAccount2.Id)
				// there should be an err
				So(err, ShouldBeNil)
				So(participants, ShouldNotBeNil)
				So(len(participants), ShouldEqual, 2)
			})
		})
	})
}
<commit_msg>Social: run channel tests only for standard operations, remove specific test cases for other channel types<commit_after>package main

import (
	"socialapi/models"
	"socialapi/rest"
	"testing"

	. "github.com/smartystreets/goconvey/convey"
)

func TestChannelCreation(t *testing.T) {
	Convey("while  testing channel", t, func() {
		Convey("First Create Users", func() {
			account1 := models.NewAccount()
			account1.OldId = AccountOldId.Hex()
			account, err := rest.CreateAccount(account1)
			So(err, ShouldBeNil)
			So(account, ShouldNotBeNil)

			nonOwnerAccount := models.NewAccount()
			nonOwnerAccount.OldId = AccountOldId2.Hex()
			nonOwnerAccount, err = rest.CreateAccount(nonOwnerAccount)
			So(err, ShouldBeNil)
			So(nonOwnerAccount, ShouldNotBeNil)

			Convey("we should be able to create it", func() {
				channel1, err := rest.CreateChannelByGroupNameAndType(account1.Id, "testgroup", models.Channel_TYPE_CHAT)
				So(err, ShouldBeNil)
				So(channel1, ShouldNotBeNil)

				Convey("owner should be able to update it", func() {
					updatedPurpose := "another purpose from the paradise"
					channel1.Purpose = updatedPurpose

					channel2, err := rest.UpdateChannel(channel1)
					So(err, ShouldBeNil)
					So(channel2, ShouldNotBeNil)

					So(channel1.Purpose, ShouldEqual, channel1.Purpose)
				})
				Convey("non-owner should not be able to update it", func() {
					updatedPurpose := "another purpose from the paradise"
					channel1.Purpose = updatedPurpose
					channel1.CreatorId = nonOwnerAccount.Id

					channel2, err := rest.UpdateChannel(channel1)
					So(err, ShouldNotBeNil)
					So(channel2, ShouldBeNil)
				})
			})

			Convey("normal user shouldnt be able to add new participants to pinned activity channel", func() {
				channel1, err := rest.CreateChannelByGroupNameAndType(account1.Id, "testgroup", models.Channel_TYPE_PINNED_ACTIVITY)
				So(err, ShouldBeNil)
				So(channel1, ShouldNotBeNil)

				channelParticipant, err := rest.AddChannelParticipant(channel1.Id, nonOwnerAccount.Id, nonOwnerAccount.Id)
				// there should be an err
				So(err, ShouldNotBeNil)
				// channel should be nil
				So(channelParticipant, ShouldBeNil)
			})

			Convey("normal user should be able to add new participants to chat channel", func() {
				channel1, err := rest.CreateChannelByGroupNameAndType(account1.Id, "testgroup", models.Channel_TYPE_CHAT)
				So(err, ShouldBeNil)
				So(channel1, ShouldNotBeNil)

				channelParticipant, err := rest.AddChannelParticipant(channel1.Id, nonOwnerAccount.Id, nonOwnerAccount.Id)
				// there should be an err
				So(err, ShouldBeNil)
				// channel should be nil
				So(channelParticipant, ShouldNotBeNil)
			})

			Convey("owner should be able to remove participants from chat channel it", func() {
				channel1, err := rest.CreateChannelByGroupNameAndType(account1.Id, "testgroup", models.Channel_TYPE_CHAT)
				So(err, ShouldBeNil)
				So(channel1, ShouldNotBeNil)

				channelParticipant, err := rest.AddChannelParticipant(channel1.Id, account1.Id, nonOwnerAccount.Id)
				// there should be an err
				So(err, ShouldBeNil)
				// channel should be nil
				So(channelParticipant, ShouldNotBeNil)

				_, err = rest.DeleteChannelParticipant(channel1.Id, account1.Id, nonOwnerAccount.Id)
				// there should be an err
				So(err, ShouldBeNil)
			})

			Convey("owner should be able list participants", func() {
				channel1, err := rest.CreateChannelByGroupNameAndType(account1.Id, "testgroup", models.Channel_TYPE_DEFAULT)
				So(err, ShouldBeNil)
				So(channel1, ShouldNotBeNil)

				// add first participant
				channelParticipant1, err := rest.AddChannelParticipant(channel1.Id, account1.Id, nonOwnerAccount.Id)
				// there should be an err
				So(err, ShouldBeNil)
				// channel should be nil
				So(channelParticipant1, ShouldNotBeNil)

				nonOwnerAccount2 := models.NewAccount()
				nonOwnerAccount2.OldId = AccountOldId3.Hex()
				nonOwnerAccount2, err = rest.CreateAccount(nonOwnerAccount2)
				So(err, ShouldBeNil)
				So(nonOwnerAccount2, ShouldNotBeNil)

				channelParticipant2, err := rest.AddChannelParticipant(channel1.Id, account1.Id, nonOwnerAccount2.Id)
				// there should be an err
				So(err, ShouldBeNil)
				// channel should be nil
				So(channelParticipant2, ShouldNotBeNil)

				participants, err := rest.ListChannelParticipants(channel1.Id, account1.Id)
				// there should be an err
				So(err, ShouldBeNil)
				So(participants, ShouldNotBeNil)
				So(len(participants), ShouldEqual, 2)
			})

			Convey("normal user should be able to list participants", func() {
				channel1, err := rest.CreateChannelByGroupNameAndType(account1.Id, "testgroup", models.Channel_TYPE_DEFAULT)
				So(err, ShouldBeNil)
				So(channel1, ShouldNotBeNil)

				// add first participant
				channelParticipant1, err := rest.AddChannelParticipant(channel1.Id, account1.Id, nonOwnerAccount.Id)
				// there should be an err
				So(err, ShouldBeNil)
				// channel should be nil
				So(channelParticipant1, ShouldNotBeNil)

				nonOwnerAccount2 := models.NewAccount()
				nonOwnerAccount2.OldId = AccountOldId3.Hex()
				nonOwnerAccount2, err = rest.CreateAccount(nonOwnerAccount2)
				So(err, ShouldBeNil)
				So(nonOwnerAccount2, ShouldNotBeNil)

				channelParticipant2, err := rest.AddChannelParticipant(channel1.Id, account1.Id, nonOwnerAccount2.Id)
				// there should be an err
				So(err, ShouldBeNil)
				// channel should be nil
				So(channelParticipant2, ShouldNotBeNil)

				participants, err := rest.ListChannelParticipants(channel1.Id, nonOwnerAccount2.Id)
				// there should be an err
				So(err, ShouldBeNil)
				So(participants, ShouldNotBeNil)
				So(len(participants), ShouldEqual, 2)
			})
		})
	})
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"os"
	"time"
)

/****************************************************

说明:
	1. 区别 os.pipe() 和 io.pipe()
		- 2个lib的对外操作接口一致, 但数据类型不同.
		- 理解 reader 和 writer 操作行为
		- 读取操作 和 写入操作
			- 读取操作, 新启一个go例程, 阻塞等数据
			- 为何是阻塞的? 加入 sleep()作了验证.

	2. 理解静态类型语言和动态类型语言, 本质差异:
		- 动态类型:
			- 如Python, 这里2个操作函数, 完全可以合并成一个.
			- 对于2个lib中 reader 和 writer 参数类型不同.
			- Python是可以等到运行时, 再确定参数类型.
			- 本质上是变量名的复用, 2个不同类型的变量, 用同一个参数名而已.
		- 静态类型:
			- go这里,就不可以合并2个子函数
			- 因为 reader 和 writer 的数据类型不同
			- go在编译时, 就要确定参数类型, 传入的参数类型要匹配, 不匹配, 就要写成2个.
			- go并能定义一个 temp, 把 A 和 B 不同类型, 强制转换赋值给 temp.
		- 数据类型不同 vs 行为一致:
			- python 是真鸭子类型, 可以合并API操作逻辑, 动态类型的特点.
			- go 无法在数据类型不同的前提下, 合并API操作逻辑.
			- go 并不是真的鸭子类型. (虽然面向接口编程, 很像)

	3. 理解面向接口编程:
		- 拆开 数据 和 行为
		- 本质上是面向行为编程, 统一行为, 但没有约束数据.
		- 行为统一, 可认为是 "同源 or 相近"
		- 数据类型根源上若不同, 那依然是不同的. 很多代码逻辑是不可以直接合并的.
		- 数据不同, 哪怕行为一致, 也是不同的.(这其实是静态型语言go的锅)
		- 理解go作为静态类型语言本身的限制.

****************************************************/

func main() {
	fileBasePipe() // 基于文件io
	fmt.Println("---------")
	inMemorySyncPipe() // 基于内存io
}

func fileBasePipe() {
	reader, writer, err := os.Pipe() // 区别: os包
	doByOSPipe(reader, writer, err)
}

func inMemorySyncPipe() {
	reader, writer := io.Pipe() // 区别: io包
	doByIOPipe(reader, writer)
}

func doByOSPipe(reader *os.File, writer *os.File, err error) {
	if err != nil {
		fmt.Printf("Error: Coundn't create pipe: %s\n", err)
	}

	//----------------------------------------------
	// 读取操作:
	//		- 新起一个go例程, 阻塞等.
	//		- 写入操作 sleep 多久, 则等多久.
	//----------------------------------------------

	go func() {
		output := make([]byte, 100) // 输出缓冲

		// 读取操作:
		//		- 从下面的 input读来, 写到 output中.
		n, err := reader.Read(output)
		if err != nil {
			fmt.Printf("Error: Couldn't read data from pipe: %s\n", err)
		}
		fmt.Printf("Read %d byte(s).\nresult: %s\n", n, output)
	}()

	//----------------------------------------------
	// 写入操作:
	//----------------------------------------------

	input := make([]byte, 26) // 写入缓冲

	// 准备数据:
	for i := 65; i <= 90; i++ {
		input[i-65] = byte(i)
	}

	time.Sleep(2 * time.Second) // 加入睡眠, 让 读取go例程, 等待数据.

	// 写入操作:
	n, err := writer.Write(input) // 通过writer()写入数据.
	if err != nil {
		fmt.Printf("Error: Couldn't write data to pipe: %s\n", err)
	}

	fmt.Printf("Written %d byte(s).\n", n)
	time.Sleep(200 * time.Millisecond)

}

func doByIOPipe(reader *io.PipeReader, writer *io.PipeWriter) {
	//----------------------------------------------
	// 读取操作:
	//		- 新起一个go例程, 阻塞等.
	//		- 写入操作 sleep 多久, 则等多久.
	//----------------------------------------------

	go func() {
		output := make([]byte, 100)
		n, err := reader.Read(output)
		if err != nil {
			fmt.Printf("Error: Couldn't read data from pipe: %s\n", err)
		}
		fmt.Printf("Read %d byte(s).\n", n)
	}()

	//----------------------------------------------
	// 写入操作:
	//----------------------------------------------

	input := make([]byte, 26)

	for i := 65; i <= 90; i++ {
		input[i-65] = byte(i)
	}

	n, err := writer.Write(input)
	if err != nil {
		fmt.Printf("Error: Couldn't write data to pipe: %s\n", err)
	}

	fmt.Printf("Written %d byte(s).\n", n)
	time.Sleep(200 * time.Millisecond)
}
<commit_msg>update - 完善注释.<commit_after>package main

import (
	"fmt"
	"io"
	"os"
	"time"
)

/****************************************************

说明:
	1. 区别 os.pipe() 和 io.pipe()
		- 2个lib的对外操作接口一致, 但数据类型不同.
		- 理解 reader 和 writer 操作行为
		- 读取操作 和 写入操作
			- 读取操作, 新启一个go例程, 阻塞等数据
			- 为何是阻塞的? 加入 sleep()作了验证.

	2. 理解静态类型语言和动态类型语言, 本质差异:
		- 动态类型:
			- 如Python, 这里2个操作函数, 完全可以合并成一个.
			- 对于2个lib中 reader 和 writer 参数类型不同.
			- Python是可以等到运行时, 再确定参数类型.
			- 本质上是变量名的复用, 2个不同类型的变量, 用同一个参数名而已.
		- 静态类型:
			- go这里,就不可以合并2个子函数
			- 因为 reader 和 writer 的数据类型不同
			- go在编译时, 就要确定参数类型, 传入的参数类型要匹配, 不匹配, 就要写成2个.
			- go并能定义一个 temp, 把 A 和 B 不同类型, 强制转换赋值给 temp.
		- 数据类型不同 vs 行为一致:
			- python 是真鸭子类型, 可以合并API操作逻辑, 动态类型的特点.
			- go 无法在数据类型不同的前提下, 合并API操作逻辑.
			- go 并不是真的鸭子类型. (虽然面向接口编程, 很像)

	3. 理解面向接口编程:
		- 拆开 数据 和 行为
		- 本质上是面向行为编程,
		- 实现函数多态:
			- 表面上, 统一行为操作.
			- 形参设计: 利用 interface {} 扩展
			- 行为优先, 若数据类型不同, 扩展新的 interface{} 用以支持 "一致的行为"
			- 数据 为 行为 服务.
			- 若行为统一, 根源数据类型不同, 则相似逻辑代码不可直接合并.
			- 解决办法:
				- 扩展根源数据类型, 即: 统一 A, B 类型的 interface{}源
				- 这样 A, B 的 数据源(interface) 和 操作行为, 都得到统一.
				- 实现函数多态.
				- - 理解go作为静态类型语言本身的限制.
	4. 函数多态设计:
		- 基于 interface{} 实现
		- 基于反射 reflect 实现

****************************************************/

func main() {
	fileBasePipe() // 基于文件io
	fmt.Println("---------")
	inMemorySyncPipe() // 基于内存io
}

func fileBasePipe() {
	reader, writer, err := os.Pipe() // 区别: os包
	doByOSPipe(reader, writer, err)
}

func inMemorySyncPipe() {
	reader, writer := io.Pipe() // 区别: io包
	doByIOPipe(reader, writer)
}

func doByOSPipe(reader *os.File, writer *os.File, err error) {
	if err != nil {
		fmt.Printf("Error: Coundn't create pipe: %s\n", err)
	}

	//----------------------------------------------
	// 读取操作:
	//		- 新起一个go例程, 阻塞等.
	//		- 写入操作 sleep 多久, 则等多久.
	//----------------------------------------------

	go func() {
		output := make([]byte, 100) // 输出缓冲

		// 读取操作:
		//		- 从下面的 input读来, 写到 output中.
		n, err := reader.Read(output)
		if err != nil {
			fmt.Printf("Error: Couldn't read data from pipe: %s\n", err)
		}
		fmt.Printf("Read %d byte(s).\nresult: %s\n", n, output)
	}()

	//----------------------------------------------
	// 写入操作:
	//----------------------------------------------

	input := make([]byte, 26) // 写入缓冲

	// 准备数据:
	for i := 65; i <= 90; i++ {
		input[i-65] = byte(i)
	}

	time.Sleep(2 * time.Second) // 加入睡眠, 让 读取go例程, 等待数据.

	// 写入操作:
	n, err := writer.Write(input) // 通过writer()写入数据.
	if err != nil {
		fmt.Printf("Error: Couldn't write data to pipe: %s\n", err)
	}

	fmt.Printf("Written %d byte(s).\n", n)
	time.Sleep(200 * time.Millisecond)

}

func doByIOPipe(reader *io.PipeReader, writer *io.PipeWriter) {
	//----------------------------------------------
	// 读取操作:
	//		- 新起一个go例程, 阻塞等.
	//		- 写入操作 sleep 多久, 则等多久.
	//----------------------------------------------

	go func() {
		output := make([]byte, 100)
		n, err := reader.Read(output)
		if err != nil {
			fmt.Printf("Error: Couldn't read data from pipe: %s\n", err)
		}
		fmt.Printf("Read %d byte(s).\n", n)
	}()

	//----------------------------------------------
	// 写入操作:
	//----------------------------------------------

	input := make([]byte, 26)

	for i := 65; i <= 90; i++ {
		input[i-65] = byte(i)
	}

	n, err := writer.Write(input)
	if err != nil {
		fmt.Printf("Error: Couldn't write data to pipe: %s\n", err)
	}

	fmt.Printf("Written %d byte(s).\n", n)
	time.Sleep(200 * time.Millisecond)
}
<|endoftext|>


<commit_before>package db

import "github.com/pkg/errors"

func DeleteConferenceComponentsByIDAndName(tx *Tx, conferenceID string, names ...string) error {
	stmt := getStmtBuf()
	defer releaseStmtBuf(stmt)

	l := len(names)
	if l == 0 {
		return errors.New("empty list of names")
	}

	stmt.WriteString(`DELETE FROM `)
	stmt.WriteString(ConferenceComponentTable)
	stmt.WriteString(` WHERE conference_id = ? AND name IN (`)
	for i := range names {
		stmt.WriteByte('?')
		if i < l - 1 {
			stmt.WriteByte(',')
		}
	}
	stmt.WriteString(`)`)

	args := make([]interface{}, len(names)+1)
	args[0] = conferenceID
	for i, name := range names {
		args[i+1] = name
	}
	if _, err := tx.Exec(stmt.String(), args...); err != nil {
		return errors.Wrap(err, "failed to execute delete statement")
	}

	return nil
}

func UpsertConferenceComponentsByIDAndName(tx *Tx, conferenceID string, values map[string]string) error {
	stmt := getStmtBuf()
	defer releaseStmtBuf(stmt)

	l := len(values)
	if l == 0 {
		return errors.New("empty value map")
	}

	stmt.WriteString(`INSERT INTO `)
	stmt.WriteString(ConferenceComponentTable)
	stmt.WriteString(` (conference_id, name, value) VALUES `)

	var args []interface{}
	i := 0
	for k, v := range values {
		args = append(args, conferenceID, k, v)
		stmt.WriteString(`(?, ?, ?)`)
		if i < l - 1 {
			stmt.WriteByte(',')
		}
		i++
	}

	stmt.WriteString(` ON DUPLICATE UPDATE value = VALUES(value)`)
	if _, err := tx.Exec(stmt.String(), args...); err != nil {
		return errors.Wrap(err, "failed to execute insert statement")
	}

	return nil
}

func (ccl *ConferenceComponentList) LoadByConferenceID(tx *Tx, cid string) error {
	stmt := getStmtBuf()
	defer releaseStmtBuf(stmt)

	stmt.WriteString(`SELECT `)
	stmt.WriteString(ConferenceComponentStdSelectColumns)
	stmt.WriteString(` FROM `)
	stmt.WriteString(ConferenceComponentTable)
	stmt.WriteString(` WHERE conference_id = ?`)

	rows, err := tx.Query(stmt.String(), cid)
	if err != nil {
		return errors.Wrap(err, "failed to execute query for conference component")
	}

	var res ConferenceComponentList
	for rows.Next() {
		var row ConferenceComponent
		if err := row.Scan(rows); err != nil {
			return errors.Wrap(err, "failed to scan conference component")
		}
		res = append(res, row)
	}

	*ccl = res
	return nil
}
<commit_msg>Fix SQL<commit_after>package db

import "github.com/pkg/errors"

func DeleteConferenceComponentsByIDAndName(tx *Tx, conferenceID string, names ...string) error {
	stmt := getStmtBuf()
	defer releaseStmtBuf(stmt)

	l := len(names)
	if l == 0 {
		return errors.New("empty list of names")
	}

	stmt.WriteString(`DELETE FROM `)
	stmt.WriteString(ConferenceComponentTable)
	stmt.WriteString(` WHERE conference_id = ? AND name IN (`)
	for i := range names {
		stmt.WriteByte('?')
		if i < l - 1 {
			stmt.WriteByte(',')
		}
	}
	stmt.WriteString(`)`)

	args := make([]interface{}, len(names)+1)
	args[0] = conferenceID
	for i, name := range names {
		args[i+1] = name
	}
	if _, err := tx.Exec(stmt.String(), args...); err != nil {
		return errors.Wrap(err, "failed to execute delete statement")
	}

	return nil
}

func UpsertConferenceComponentsByIDAndName(tx *Tx, conferenceID string, values map[string]string) error {
	stmt := getStmtBuf()
	defer releaseStmtBuf(stmt)

	l := len(values)
	if l == 0 {
		return errors.New("empty value map")
	}

	stmt.WriteString(`INSERT INTO `)
	stmt.WriteString(ConferenceComponentTable)
	stmt.WriteString(` (conference_id, name, value) VALUES `)

	var args []interface{}
	i := 0
	for k, v := range values {
		args = append(args, conferenceID, k, v)
		stmt.WriteString(`(?, ?, ?)`)
		if i < l - 1 {
			stmt.WriteByte(',')
		}
		i++
	}

	stmt.WriteString(` ON DUPLICATE KEY UPDATE value = VALUES(value)`)
	if _, err := tx.Exec(stmt.String(), args...); err != nil {
		return errors.Wrap(err, "failed to execute insert statement")
	}

	return nil
}

func (ccl *ConferenceComponentList) LoadByConferenceID(tx *Tx, cid string) error {
	stmt := getStmtBuf()
	defer releaseStmtBuf(stmt)

	stmt.WriteString(`SELECT `)
	stmt.WriteString(ConferenceComponentStdSelectColumns)
	stmt.WriteString(` FROM `)
	stmt.WriteString(ConferenceComponentTable)
	stmt.WriteString(` WHERE conference_id = ?`)

	rows, err := tx.Query(stmt.String(), cid)
	if err != nil {
		return errors.Wrap(err, "failed to execute query for conference component")
	}

	var res ConferenceComponentList
	for rows.Next() {
		var row ConferenceComponent
		if err := row.Scan(rows); err != nil {
			return errors.Wrap(err, "failed to scan conference component")
		}
		res = append(res, row)
	}

	*ccl = res
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"time"
)

var (
	readFormat  = "RECEIVE %-8v: %v\n"
	writeFormat = "SEND    %-8v: %v\n"
)

// Writes to stdout read data from channel
func readFromChan(channel <-chan string, prefix string) {
	// channel <- "It'll not work"

	for data := range channel {
		fmt.Printf(readFormat, prefix, data)
	}
}

// Sends string by 1 symbol to channel
func writeToChan(channel chan <- string, data, prefix string) {
	// <-channel // "It'll not work"

	for _, symbol := range data {
		fmt.Printf(writeFormat, prefix, string(symbol))
		channel <- string(symbol)
	}
}

func main() {
	sendData := ""
	unBufferedChannel := make(chan string)
	bufferedChannel := make(chan string, 10)

	defer close(bufferedChannel)
	defer close(unBufferedChannel)

	// channel := unBufferedChannel // fatal error: all goroutines are asleep - deadlock!
	channel := bufferedChannel
	sendData = "FirstData"
	fmt.Printf(writeFormat, "First", sendData)

	channel <- sendData

	fmt.Printf(readFormat, "First", <-channel)
	fmt.Println("\n------------------------------------------------------------------\n")

	// Unbuffered channel in goroutines

	go readFromChan(unBufferedChannel, "Second")

	writeToChan(unBufferedChannel, "abcdef", "Second")

	time.Sleep(100 * time.Millisecond)
	fmt.Println("\n------------------------------------------------------------------\n")

	// buffered channel in goroutines

	go readFromChan(bufferedChannel, "Third")

	writeToChan(bufferedChannel, "abcdef", "Third")

	time.Sleep(100 * time.Millisecond)
}
<commit_msg>fix lesson_23_type_chan<commit_after>package main

import (
	"fmt"
	"time"
)

var (
	readFormat  = "RECEIVE %-8v: %v\n"
	writeFormat = "SEND    %-8v: %v\n"
)

// Writes to stdout read data from channel
func readFromChan(channel <-chan string, prefix string) {
	// channel <- "It'll not work"

	for data := range channel {
		fmt.Printf(readFormat, prefix, data)
	}
}

// Sends string by 1 symbol to channel
func writeToChan(channel chan <- string, data, prefix string) {
	// <-channel // "It'll not work"

	for _, symbol := range data {
		fmt.Printf(writeFormat, prefix, string(symbol))
		channel <- string(symbol)
	}
}

func main() {
	unBufferedChannel := make(chan string)
	bufferedChannel := make(chan string, 10)

	defer close(bufferedChannel)
	defer close(unBufferedChannel)

	// channel := unBufferedChannel // fatal error: all goroutines are asleep - deadlock!
	channel := bufferedChannel
	fmt.Printf(writeFormat, "First", "FirstData")

	channel <- "FirstData"

	fmt.Printf(readFormat, "First", <-channel)
	fmt.Println("\n------------------------------------------------------------------\n")

	// Unbuffered channel in goroutines

	go readFromChan(unBufferedChannel, "Second")

	writeToChan(unBufferedChannel, "abcdef", "Second")

	time.Sleep(100 * time.Millisecond)
	fmt.Println("\n------------------------------------------------------------------\n")

	// buffered channel in goroutines

	go readFromChan(bufferedChannel, "Third")

	writeToChan(bufferedChannel, "abcdef", "Third")

	time.Sleep(100 * time.Millisecond)
}
<|endoftext|>


<commit_before>package core

import (
	"testing"

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

var impureFunction = NewLazyFunction(
	NewSignature([]string{"x"}, nil, "", nil, nil, ""),
	func(ts ...*Thunk) Value {
		return NewOutput(ts[0])
	})

func TestThunkEvalWithNotCallable(t *testing.T) {
	assert.Equal(t, "TypeError", PApp(Nil).Eval().(ErrorType).name)
}

func TestThunkEvalWithImpureFunctionCall(t *testing.T) {
	assert.Equal(t, "TypeError", PApp(impureFunction, Nil).Eval().(ErrorType).name)
}

func TestThunkEvalByCallingError(t *testing.T) {
	e := PApp(NewError("Apple", "pen.")).Eval().(ErrorType)
	t.Log(e)
	assert.Equal(t, 1, len(e.callTrace))
}

func TestThunkEvalByCallingErrorTwice(t *testing.T) {
	e := PApp(PApp(NewError("Apple", "pen."))).Eval().(ErrorType)
	t.Log(e)
	assert.Equal(t, 2, len(e.callTrace))
}

func TestThunkEvalOutput(t *testing.T) {
	s := NewString("foo")
	assert.Equal(t, s.Eval(), PApp(impureFunction, s).EvalOutput())
}

func TestThunkEvalOutputWithNonOutput(t *testing.T) {
	for _, th := range []*Thunk{Nil, PApp(identity, Nil)} {
		v := th.EvalOutput()
		err, ok := v.(ErrorType)
		t.Logf("%#v\n", v)
		assert.True(t, ok)
		assert.Equal(t, err.name, "TypeError")
	}
}

func TestThunkEvalOutputWithError(t *testing.T) {
	v := OutOfRangeError().EvalOutput()
	err, ok := v.(ErrorType)
	t.Logf("%#v\n", v)
	assert.True(t, ok)
	assert.Equal(t, err.name, "OutOfRangeError")
}
<commit_msg>Test assertValueIsNormal function<commit_after>package core

import (
	"testing"

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

var impureFunction = NewLazyFunction(
	NewSignature([]string{"x"}, nil, "", nil, nil, ""),
	func(ts ...*Thunk) Value {
		return NewOutput(ts[0])
	})

func TestThunkEvalWithNotCallable(t *testing.T) {
	assert.Equal(t, "TypeError", PApp(Nil).Eval().(ErrorType).name)
}

func TestThunkEvalWithImpureFunctionCall(t *testing.T) {
	assert.Equal(t, "TypeError", PApp(impureFunction, Nil).Eval().(ErrorType).name)
}

func TestThunkEvalByCallingError(t *testing.T) {
	e := PApp(NewError("Apple", "pen.")).Eval().(ErrorType)
	t.Log(e)
	assert.Equal(t, 1, len(e.callTrace))
}

func TestThunkEvalByCallingErrorTwice(t *testing.T) {
	e := PApp(PApp(NewError("Apple", "pen."))).Eval().(ErrorType)
	t.Log(e)
	assert.Equal(t, 2, len(e.callTrace))
}

func TestThunkEvalOutput(t *testing.T) {
	s := NewString("foo")
	assert.Equal(t, s.Eval(), PApp(impureFunction, s).EvalOutput())
}

func TestThunkEvalOutputWithNonOutput(t *testing.T) {
	for _, th := range []*Thunk{Nil, PApp(identity, Nil)} {
		v := th.EvalOutput()
		err, ok := v.(ErrorType)
		t.Logf("%#v\n", v)
		assert.True(t, ok)
		assert.Equal(t, err.name, "TypeError")
	}
}

func TestThunkEvalOutputWithError(t *testing.T) {
	v := OutOfRangeError().EvalOutput()
	err, ok := v.(ErrorType)
	t.Logf("%#v\n", v)
	assert.True(t, ok)
	assert.Equal(t, err.name, "OutOfRangeError")
}

func TestAssertValueIsNormal(t *testing.T) {
	defer func() {
		if r := recover(); r == nil {
			t.Fail()
		}
	}()

	assertValueIsNormal("This", Nil)
}
<|endoftext|>


<commit_before>/*
Package pfsutil provides utility functions that wrap a pfs.APIClient
to make the calling code slightly cleaner.
*/
package pfsutil

import (
	"io"
	"math"

	"github.com/pachyderm/pachyderm/src/pfs"
	"github.com/pachyderm/pachyderm/src/pfs/drive"
	"go.pedge.io/proto/stream"
	"golang.org/x/net/context"
)

const chunkSize = 4096

func CreateRepo(apiClient pfs.APIClient, repoName string) error {
	_, err := apiClient.CreateRepo(
		context.Background(),
		&pfs.CreateRepoRequest{
			Repo: &pfs.Repo{
				Name: repoName,
			},
		},
	)
	return err
}

func InspectRepo(apiClient pfs.APIClient, repoName string) (*pfs.RepoInfo, error) {
	repoInfo, err := apiClient.InspectRepo(
		context.Background(),
		&pfs.InspectRepoRequest{
			Repo: &pfs.Repo{
				Name: repoName,
			},
		},
	)
	if err != nil {
		return nil, err
	}
	return repoInfo, nil
}

func ListRepo(apiClient pfs.APIClient) ([]*pfs.RepoInfo, error) {
	repoInfos, err := apiClient.ListRepo(
		context.Background(),
		&pfs.ListRepoRequest{},
	)
	if err != nil {
		return nil, err
	}
	return repoInfos.RepoInfo, nil
}

func DeleteRepo(apiClient pfs.APIClient, repoName string) error {
	_, err := apiClient.DeleteRepo(
		context.Background(),
		&pfs.DeleteRepoRequest{
			Repo: &pfs.Repo{
				Name: repoName,
			},
		},
	)
	return err
}

func StartCommit(apiClient pfs.APIClient, repoName string, parentCommit string) (*pfs.Commit, error) {
	commit, err := apiClient.StartCommit(
		context.Background(),
		&pfs.StartCommitRequest{
			Parent: &pfs.Commit{
				Repo: &pfs.Repo{
					Name: repoName,
				},
				Id: parentCommit,
			},
		},
	)
	if err != nil {
		return nil, err
	}
	return commit, nil
}

func FinishCommit(apiClient pfs.APIClient, repoName string, commitID string) error {
	_, err := apiClient.FinishCommit(
		context.Background(),
		&pfs.FinishCommitRequest{
			Commit: &pfs.Commit{
				Repo: &pfs.Repo{
					Name: repoName,
				},
				Id: commitID,
			},
		},
	)
	return err
}

func InspectCommit(apiClient pfs.APIClient, repoName string, commitID string) (*pfs.CommitInfo, error) {
	commitInfo, err := apiClient.InspectCommit(
		context.Background(),
		&pfs.InspectCommitRequest{
			Commit: &pfs.Commit{
				Repo: &pfs.Repo{
					Name: repoName,
				},
				Id: commitID,
			},
		},
	)
	if err != nil {
		return nil, err
	}
	return commitInfo, nil
}

func ListCommit(apiClient pfs.APIClient, repoNames []string) ([]*pfs.CommitInfo, error) {
	var repos []*pfs.Repo
	for _, repoName := range repoNames {
		repos = append(repos, &pfs.Repo{Name: repoName})
	}
	commitInfos, err := apiClient.ListCommit(
		context.Background(),
		&pfs.ListCommitRequest{
			Repo: repos,
		},
	)
	if err != nil {
		return nil, err
	}
	return commitInfos.CommitInfo, nil
}

func DeleteCommit(apiClient pfs.APIClient, repoName string, commitID string) error {
	_, err := apiClient.DeleteCommit(
		context.Background(),
		&pfs.DeleteCommitRequest{
			Commit: &pfs.Commit{
				Repo: &pfs.Repo{
					Name: repoName,
				},
				Id: commitID,
			},
		},
	)
	return err
}

func PutBlock(apiClient drive.APIClient, reader io.Reader) (*drive.Block, error) {
	putBlockClient, err := apiClient.PutBlock(context.Background())
	if err != nil {
		return nil, err
	}
	if _, err := io.Copy(protostream.NewStreamingBytesWriter(putBlockClient), reader); err != nil {
		return nil, err
	}
	return putBlockClient.CloseAndRecv()
}

func GetBlock(apiClient drive.APIClient, hash string, offsetBytes uint64) (io.Reader, error) {
	apiGetBlockClient, err := apiClient.GetBlock(
		context.Background(),
		&drive.GetBlockRequest{
			Block: &drive.Block{
				Hash: hash,
			},
			OffsetBytes: offsetBytes,
		},
	)
	if err != nil {
		return nil, err
	}
	return protostream.NewStreamingBytesReader(apiGetBlockClient), nil
}

func InspectBlock(apiClient drive.APIClient, hash string) (*drive.BlockInfo, error) {
	blockInfo, err := apiClient.InspectBlock(
		context.Background(),
		&drive.InspectBlockRequest{
			Block: &drive.Block{
				Hash: hash,
			},
		},
	)
	if err != nil {
		return nil, err
	}
	return blockInfo, nil
}

func ListBlock(apiClient drive.APIClient) ([]*drive.BlockInfo, error) {
	blockInfos, err := apiClient.ListBlock(
		context.Background(),
		&drive.ListBlockRequest{},
	)
	if err != nil {
		return nil, err
	}
	return blockInfos.BlockInfo, nil
}

func PutFile(apiClient pfs.APIClient, repoName string, commitID string, path string, offset int64, reader io.Reader) (_ int, retErr error) {
	putFileClient, err := apiClient.PutFile(context.Background())
	if err != nil {
		return 0, err
	}
	defer func() {
		if _, err := putFileClient.CloseAndRecv(); err != nil && retErr == nil {
			retErr = err
		}
	}()
	request := pfs.PutFileRequest{
		File: &pfs.File{
			Commit: &pfs.Commit{
				Repo: &pfs.Repo{
					Name: repoName,
				},
				Id: commitID,
			},
			Path: path,
		},
		FileType:    pfs.FileType_FILE_TYPE_REGULAR,
		OffsetBytes: offset,
	}
	var size int
	for {
		value := make([]byte, chunkSize)
		iSize, err := reader.Read(value)
		if err != nil {
			if err == io.EOF {
				break
			}
			return 0, err
		}
		request.Value = value[0:iSize]
		size += iSize
		if err := putFileClient.Send(&request); err != nil {
			return 0, err
		}
	}
	if err != nil && err != io.EOF {
		return 0, err
	}
	return size, err
}

func GetFile(apiClient pfs.APIClient, repoName string, commitID string, path string, offset int64, size int64, shard *pfs.Shard, writer io.Writer) error {
	if size == 0 {
		size = math.MaxInt64
	}
	apiGetFileClient, err := apiClient.GetFile(
		context.Background(),
		&pfs.GetFileRequest{
			File: &pfs.File{
				Commit: &pfs.Commit{
					Repo: &pfs.Repo{
						Name: repoName,
					},
					Id: commitID,
				},
				Path: path,
			},
			Shard:       shard,
			OffsetBytes: offset,
			SizeBytes:   size,
		},
	)
	if err != nil {
		return err
	}
	if err := protostream.WriteFromStreamingBytesClient(apiGetFileClient, writer); err != nil {
		return err
	}
	return nil
}

func InspectFile(apiClient pfs.APIClient, repoName string, commitID string, path string, shard *pfs.Shard) (*pfs.FileInfo, error) {
	fileInfo, err := apiClient.InspectFile(
		context.Background(),
		&pfs.InspectFileRequest{
			File: &pfs.File{
				Commit: &pfs.Commit{
					Repo: &pfs.Repo{
						Name: repoName,
					},
					Id: commitID,
				},
				Path: path,
			},
			Shard: shard,
		},
	)
	if err != nil {
		return nil, err
	}
	return fileInfo, nil
}

func ListFile(apiClient pfs.APIClient, repoName string, commitID string, path string, shard *pfs.Shard) ([]*pfs.FileInfo, error) {
	fileInfos, err := apiClient.ListFile(
		context.Background(),
		&pfs.ListFileRequest{
			File: &pfs.File{
				Commit: &pfs.Commit{
					Repo: &pfs.Repo{
						Name: repoName,
					},
					Id: commitID,
				},
				Path: path,
			},
			Shard: shard,
		},
	)
	if err != nil {
		return nil, err
	}
	return fileInfos.FileInfo, nil
}

func ListChange(apiClient pfs.APIClient, repoName string, commitID string, path string, shard *pfs.Shard) ([]*pfs.Change, error) {
	changes, err := apiClient.ListChange(
		context.Background(),
		&pfs.ListChangeRequest{
			File: &pfs.File{
				Commit: &pfs.Commit{
					Repo: &pfs.Repo{
						Name: repoName,
					},
					Id: commitID,
				},
				Path: path,
			},
			Shard: shard,
		},
	)
	if err != nil {
		return nil, err
	}
	return changes.Change, nil
}

func DeleteFile(apiClient pfs.APIClient, repoName string, commitID string, path string) error {
	_, err := apiClient.DeleteFile(
		context.Background(),
		&pfs.DeleteFileRequest{
			File: &pfs.File{
				Commit: &pfs.Commit{
					Repo: &pfs.Repo{
						Name: repoName,
					},
					Id: commitID,
				},
				Path: path,
			},
		},
	)
	return err
}

func MakeDirectory(apiClient pfs.APIClient, repoName string, commitID string, path string) (retErr error) {
	putFileClient, err := apiClient.PutFile(context.Background())
	if err != nil {
		return err
	}
	defer func() {
		if _, err := putFileClient.CloseAndRecv(); err != nil && retErr == nil {
			retErr = err
		}
	}()
	return putFileClient.Send(
		&pfs.PutFileRequest{
			File: &pfs.File{
				Commit: &pfs.Commit{
					Repo: &pfs.Repo{
						Name: repoName,
					},
					Id: commitID,
				},
				Path: path,
			},
			FileType: pfs.FileType_FILE_TYPE_DIR,
		},
	)
}

func InspectServer(clusterAPIClient pfs.ClusterAPIClient, serverID string) (*pfs.ServerInfo, error) {
	return clusterAPIClient.InspectServer(
		context.Background(),
		&pfs.InspectServerRequest{
			Server: &pfs.Server{
				Id: serverID,
			},
		},
	)
}

func ListServer(clusterAPIClient pfs.ClusterAPIClient) ([]*pfs.ServerInfo, error) {
	serverInfos, err := clusterAPIClient.ListServer(
		context.Background(),
		&pfs.ListServerRequest{},
	)
	if err != nil {
		return nil, err
	}
	return serverInfos.ServerInfo, nil
}

func PullDiff(replicaAPIClient pfs.ReplicaAPIClient, repoName string, commitID string, shard uint64, writer io.Writer) error {
	apiPullDiffClient, err := replicaAPIClient.PullDiff(
		context.Background(),
		&pfs.PullDiffRequest{
			Commit: &pfs.Commit{
				Repo: &pfs.Repo{
					Name: repoName,
				},
				Id: commitID,
			},
			Shard: shard,
		},
	)
	if err != nil {
		return err
	}
	if err := protostream.WriteFromStreamingBytesClient(apiPullDiffClient, writer); err != nil {
		return err
	}
	return nil
}

func PushDiff(replicaAPIClient pfs.ReplicaAPIClient, repoName string, commitID string, shard uint64, reader io.Reader) (retErr error) {
	pushDiffClient, err := replicaAPIClient.PushDiff(context.Background())
	if err != nil {
		return err
	}
	defer func() {
		if _, err := pushDiffClient.CloseAndRecv(); err != nil && retErr == nil {
			retErr = err
		}
	}()
	request := pfs.PushDiffRequest{
		Commit: &pfs.Commit{
			Repo: &pfs.Repo{
				Name: repoName,
			},
			Id: commitID,
		},
		Shard: shard,
	}
	for {
		value := make([]byte, chunkSize)
		size, err := reader.Read(value)
		if err != nil {
			if err == io.EOF {
				break
			}
			return err
		}
		request.Value = value[0:size]
		if err = pushDiffClient.Send(&request); err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>Adds constructors for pfs primitives.<commit_after>/*
Package pfsutil provides utility functions that wrap a pfs.APIClient
to make the calling code slightly cleaner.
*/
package pfsutil

import (
	"io"
	"math"

	"github.com/pachyderm/pachyderm/src/pfs"
	"github.com/pachyderm/pachyderm/src/pfs/drive"
	"go.pedge.io/proto/stream"
	"golang.org/x/net/context"
)

const chunkSize = 4096

func NewRepo(repoName string) *pfs.Repo {
	return &pfs.Repo{Name: repoName}
}

func NewCommit(repoName string, commitID string) *pfs.Commit {
	return &pfs.Commit{
		Repo: &pfs.Repo{
			Name: repoName,
		},
		Id: commitID,
	}
}

func NewFile(repoName string, commitID string, path string) *pfs.File {
	return &pfs.File{
		Commit: &pfs.Commit{
			Repo: &pfs.Repo{
				Name: repoName,
			},
			Id: commitID,
		},
		Path: path,
	}
}

func CreateRepo(apiClient pfs.APIClient, repoName string) error {
	_, err := apiClient.CreateRepo(
		context.Background(),
		&pfs.CreateRepoRequest{
			Repo: &pfs.Repo{
				Name: repoName,
			},
		},
	)
	return err
}

func InspectRepo(apiClient pfs.APIClient, repoName string) (*pfs.RepoInfo, error) {
	repoInfo, err := apiClient.InspectRepo(
		context.Background(),
		&pfs.InspectRepoRequest{
			Repo: &pfs.Repo{
				Name: repoName,
			},
		},
	)
	if err != nil {
		return nil, err
	}
	return repoInfo, nil
}

func ListRepo(apiClient pfs.APIClient) ([]*pfs.RepoInfo, error) {
	repoInfos, err := apiClient.ListRepo(
		context.Background(),
		&pfs.ListRepoRequest{},
	)
	if err != nil {
		return nil, err
	}
	return repoInfos.RepoInfo, nil
}

func DeleteRepo(apiClient pfs.APIClient, repoName string) error {
	_, err := apiClient.DeleteRepo(
		context.Background(),
		&pfs.DeleteRepoRequest{
			Repo: &pfs.Repo{
				Name: repoName,
			},
		},
	)
	return err
}

func StartCommit(apiClient pfs.APIClient, repoName string, parentCommit string) (*pfs.Commit, error) {
	commit, err := apiClient.StartCommit(
		context.Background(),
		&pfs.StartCommitRequest{
			Parent: &pfs.Commit{
				Repo: &pfs.Repo{
					Name: repoName,
				},
				Id: parentCommit,
			},
		},
	)
	if err != nil {
		return nil, err
	}
	return commit, nil
}

func FinishCommit(apiClient pfs.APIClient, repoName string, commitID string) error {
	_, err := apiClient.FinishCommit(
		context.Background(),
		&pfs.FinishCommitRequest{
			Commit: &pfs.Commit{
				Repo: &pfs.Repo{
					Name: repoName,
				},
				Id: commitID,
			},
		},
	)
	return err
}

func InspectCommit(apiClient pfs.APIClient, repoName string, commitID string) (*pfs.CommitInfo, error) {
	commitInfo, err := apiClient.InspectCommit(
		context.Background(),
		&pfs.InspectCommitRequest{
			Commit: &pfs.Commit{
				Repo: &pfs.Repo{
					Name: repoName,
				},
				Id: commitID,
			},
		},
	)
	if err != nil {
		return nil, err
	}
	return commitInfo, nil
}

func ListCommit(apiClient pfs.APIClient, repoNames []string) ([]*pfs.CommitInfo, error) {
	var repos []*pfs.Repo
	for _, repoName := range repoNames {
		repos = append(repos, &pfs.Repo{Name: repoName})
	}
	commitInfos, err := apiClient.ListCommit(
		context.Background(),
		&pfs.ListCommitRequest{
			Repo: repos,
		},
	)
	if err != nil {
		return nil, err
	}
	return commitInfos.CommitInfo, nil
}

func DeleteCommit(apiClient pfs.APIClient, repoName string, commitID string) error {
	_, err := apiClient.DeleteCommit(
		context.Background(),
		&pfs.DeleteCommitRequest{
			Commit: &pfs.Commit{
				Repo: &pfs.Repo{
					Name: repoName,
				},
				Id: commitID,
			},
		},
	)
	return err
}

func PutBlock(apiClient drive.APIClient, reader io.Reader) (*drive.Block, error) {
	putBlockClient, err := apiClient.PutBlock(context.Background())
	if err != nil {
		return nil, err
	}
	if _, err := io.Copy(protostream.NewStreamingBytesWriter(putBlockClient), reader); err != nil {
		return nil, err
	}
	return putBlockClient.CloseAndRecv()
}

func GetBlock(apiClient drive.APIClient, hash string, offsetBytes uint64) (io.Reader, error) {
	apiGetBlockClient, err := apiClient.GetBlock(
		context.Background(),
		&drive.GetBlockRequest{
			Block: &drive.Block{
				Hash: hash,
			},
			OffsetBytes: offsetBytes,
		},
	)
	if err != nil {
		return nil, err
	}
	return protostream.NewStreamingBytesReader(apiGetBlockClient), nil
}

func InspectBlock(apiClient drive.APIClient, hash string) (*drive.BlockInfo, error) {
	blockInfo, err := apiClient.InspectBlock(
		context.Background(),
		&drive.InspectBlockRequest{
			Block: &drive.Block{
				Hash: hash,
			},
		},
	)
	if err != nil {
		return nil, err
	}
	return blockInfo, nil
}

func ListBlock(apiClient drive.APIClient) ([]*drive.BlockInfo, error) {
	blockInfos, err := apiClient.ListBlock(
		context.Background(),
		&drive.ListBlockRequest{},
	)
	if err != nil {
		return nil, err
	}
	return blockInfos.BlockInfo, nil
}

func PutFile(apiClient pfs.APIClient, repoName string, commitID string, path string, offset int64, reader io.Reader) (_ int, retErr error) {
	putFileClient, err := apiClient.PutFile(context.Background())
	if err != nil {
		return 0, err
	}
	defer func() {
		if _, err := putFileClient.CloseAndRecv(); err != nil && retErr == nil {
			retErr = err
		}
	}()
	request := pfs.PutFileRequest{
		File: &pfs.File{
			Commit: &pfs.Commit{
				Repo: &pfs.Repo{
					Name: repoName,
				},
				Id: commitID,
			},
			Path: path,
		},
		FileType:    pfs.FileType_FILE_TYPE_REGULAR,
		OffsetBytes: offset,
	}
	var size int
	for {
		value := make([]byte, chunkSize)
		iSize, err := reader.Read(value)
		if err != nil {
			if err == io.EOF {
				break
			}
			return 0, err
		}
		request.Value = value[0:iSize]
		size += iSize
		if err := putFileClient.Send(&request); err != nil {
			return 0, err
		}
	}
	if err != nil && err != io.EOF {
		return 0, err
	}
	return size, err
}

func GetFile(apiClient pfs.APIClient, repoName string, commitID string, path string, offset int64, size int64, shard *pfs.Shard, writer io.Writer) error {
	if size == 0 {
		size = math.MaxInt64
	}
	apiGetFileClient, err := apiClient.GetFile(
		context.Background(),
		&pfs.GetFileRequest{
			File: &pfs.File{
				Commit: &pfs.Commit{
					Repo: &pfs.Repo{
						Name: repoName,
					},
					Id: commitID,
				},
				Path: path,
			},
			Shard:       shard,
			OffsetBytes: offset,
			SizeBytes:   size,
		},
	)
	if err != nil {
		return err
	}
	if err := protostream.WriteFromStreamingBytesClient(apiGetFileClient, writer); err != nil {
		return err
	}
	return nil
}

func InspectFile(apiClient pfs.APIClient, repoName string, commitID string, path string, shard *pfs.Shard) (*pfs.FileInfo, error) {
	fileInfo, err := apiClient.InspectFile(
		context.Background(),
		&pfs.InspectFileRequest{
			File: &pfs.File{
				Commit: &pfs.Commit{
					Repo: &pfs.Repo{
						Name: repoName,
					},
					Id: commitID,
				},
				Path: path,
			},
			Shard: shard,
		},
	)
	if err != nil {
		return nil, err
	}
	return fileInfo, nil
}

func ListFile(apiClient pfs.APIClient, repoName string, commitID string, path string, shard *pfs.Shard) ([]*pfs.FileInfo, error) {
	fileInfos, err := apiClient.ListFile(
		context.Background(),
		&pfs.ListFileRequest{
			File: &pfs.File{
				Commit: &pfs.Commit{
					Repo: &pfs.Repo{
						Name: repoName,
					},
					Id: commitID,
				},
				Path: path,
			},
			Shard: shard,
		},
	)
	if err != nil {
		return nil, err
	}
	return fileInfos.FileInfo, nil
}

func ListChange(apiClient pfs.APIClient, repoName string, commitID string, path string, shard *pfs.Shard) ([]*pfs.Change, error) {
	changes, err := apiClient.ListChange(
		context.Background(),
		&pfs.ListChangeRequest{
			File: &pfs.File{
				Commit: &pfs.Commit{
					Repo: &pfs.Repo{
						Name: repoName,
					},
					Id: commitID,
				},
				Path: path,
			},
			Shard: shard,
		},
	)
	if err != nil {
		return nil, err
	}
	return changes.Change, nil
}

func DeleteFile(apiClient pfs.APIClient, repoName string, commitID string, path string) error {
	_, err := apiClient.DeleteFile(
		context.Background(),
		&pfs.DeleteFileRequest{
			File: &pfs.File{
				Commit: &pfs.Commit{
					Repo: &pfs.Repo{
						Name: repoName,
					},
					Id: commitID,
				},
				Path: path,
			},
		},
	)
	return err
}

func MakeDirectory(apiClient pfs.APIClient, repoName string, commitID string, path string) (retErr error) {
	putFileClient, err := apiClient.PutFile(context.Background())
	if err != nil {
		return err
	}
	defer func() {
		if _, err := putFileClient.CloseAndRecv(); err != nil && retErr == nil {
			retErr = err
		}
	}()
	return putFileClient.Send(
		&pfs.PutFileRequest{
			File: &pfs.File{
				Commit: &pfs.Commit{
					Repo: &pfs.Repo{
						Name: repoName,
					},
					Id: commitID,
				},
				Path: path,
			},
			FileType: pfs.FileType_FILE_TYPE_DIR,
		},
	)
}

func InspectServer(clusterAPIClient pfs.ClusterAPIClient, serverID string) (*pfs.ServerInfo, error) {
	return clusterAPIClient.InspectServer(
		context.Background(),
		&pfs.InspectServerRequest{
			Server: &pfs.Server{
				Id: serverID,
			},
		},
	)
}

func ListServer(clusterAPIClient pfs.ClusterAPIClient) ([]*pfs.ServerInfo, error) {
	serverInfos, err := clusterAPIClient.ListServer(
		context.Background(),
		&pfs.ListServerRequest{},
	)
	if err != nil {
		return nil, err
	}
	return serverInfos.ServerInfo, nil
}

func PullDiff(replicaAPIClient pfs.ReplicaAPIClient, repoName string, commitID string, shard uint64, writer io.Writer) error {
	apiPullDiffClient, err := replicaAPIClient.PullDiff(
		context.Background(),
		&pfs.PullDiffRequest{
			Commit: &pfs.Commit{
				Repo: &pfs.Repo{
					Name: repoName,
				},
				Id: commitID,
			},
			Shard: shard,
		},
	)
	if err != nil {
		return err
	}
	if err := protostream.WriteFromStreamingBytesClient(apiPullDiffClient, writer); err != nil {
		return err
	}
	return nil
}

func PushDiff(replicaAPIClient pfs.ReplicaAPIClient, repoName string, commitID string, shard uint64, reader io.Reader) (retErr error) {
	pushDiffClient, err := replicaAPIClient.PushDiff(context.Background())
	if err != nil {
		return err
	}
	defer func() {
		if _, err := pushDiffClient.CloseAndRecv(); err != nil && retErr == nil {
			retErr = err
		}
	}()
	request := pfs.PushDiffRequest{
		Commit: &pfs.Commit{
			Repo: &pfs.Repo{
				Name: repoName,
			},
			Id: commitID,
		},
		Shard: shard,
	}
	for {
		value := make([]byte, chunkSize)
		size, err := reader.Read(value)
		if err != nil {
			if err == io.EOF {
				break
			}
			return err
		}
		request.Value = value[0:size]
		if err = pushDiffClient.Send(&request); err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


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

package net

import (
	"io";
	"os";
	"strings";
	"syscall";
	"testing";
)

func runEcho(fd io.ReadWriter, done chan<- int) {
	var buf [1024]byte;

	for {
		n, err := fd.Read(&buf);
		if err != nil || n == 0 {
			break
		}
		fd.Write(buf[0:n]);
	}
	done <- 1;
}

func runServe(t *testing.T, network, addr string, listening chan<- string, done chan<- int) {
	l, err := Listen(network, addr);
	if err != nil {
		t.Fatalf("net.Listen(%q, %q) = _, %v", network, addr, err)
	}
	listening <- l.Addr().String();

	for {
		fd, err := l.Accept();
		if err != nil {
			break
		}
		echodone := make(chan int);
		go runEcho(fd, echodone);
		<-echodone;	// make sure Echo stops
		l.Close();
	}
	done <- 1;
}

func connect(t *testing.T, network, addr string) {
	var laddr string;
	if network == "unixgram" {
		laddr = addr + ".local"
	}
	fd, err := Dial(network, laddr, addr);
	if err != nil {
		t.Fatalf("net.Dial(%q, %q, %q) = _, %v", network, laddr, addr, err)
	}

	b := strings.Bytes("hello, world\n");
	var b1 [100]byte;

	n, errno := fd.Write(b);
	if n != len(b) {
		t.Fatalf("fd.Write(%q) = %d, %v", b, n, errno)
	}

	n, errno = fd.Read(&b1);
	if n != len(b) {
		t.Fatalf("fd.Read() = %d, %v", n, errno)
	}
	fd.Close();
}

func doTest(t *testing.T, network, listenaddr, dialaddr string) {
	t.Logf("Test %s %s %s\n", network, listenaddr, dialaddr);
	listening := make(chan string);
	done := make(chan int);
	if network == "tcp" {
		listenaddr += ":0"	// any available port
	}
	go runServe(t, network, listenaddr, listening, done);
	addr := <-listening;	// wait for server to start
	if network == "tcp" {
		dialaddr += addr[strings.LastIndex(addr, ":"):len(addr)]
	}
	connect(t, network, dialaddr);
	<-done;	// make sure server stopped
}

func TestTCPServer(t *testing.T) {
	doTest(t, "tcp", "0.0.0.0", "127.0.0.1");
	doTest(t, "tcp", "[::]", "[::ffff:127.0.0.1]");
	doTest(t, "tcp", "[::]", "127.0.0.1");
	doTest(t, "tcp", "", "127.0.0.1");
	doTest(t, "tcp", "0.0.0.0", "[::ffff:127.0.0.1]");
}

func TestUnixServer(t *testing.T) {
	os.Remove("/tmp/gotest.net");
	doTest(t, "unix", "/tmp/gotest.net", "/tmp/gotest.net");
	os.Remove("/tmp/gotest.net");
	if syscall.OS == "linux" {
		// Test abstract unix domain socket, a Linux-ism
		doTest(t, "unix", "@gotest/net", "@gotest/net")
	}
}

func runPacket(t *testing.T, network, addr string, listening chan<- string, done chan<- int) {
	c, err := ListenPacket(network, addr);
	if err != nil {
		t.Fatalf("net.ListenPacket(%q, %q) = _, %v", network, addr, err)
	}
	listening <- c.LocalAddr().String();
	c.SetReadTimeout(10e6);	// 10ms
	var buf [1000]byte;
	for {
		n, addr, err := c.ReadFrom(&buf);
		if err == os.EAGAIN {
			if done <- 1 {
				break
			}
			continue;
		}
		if err != nil {
			break
		}
		if _, err = c.WriteTo(buf[0:n], addr); err != nil {
			t.Fatalf("WriteTo %v: %v", addr, err)
		}
	}
	c.Close();
	done <- 1;
}

func doTestPacket(t *testing.T, network, listenaddr, dialaddr string) {
	t.Logf("TestPacket %s %s %s\n", network, listenaddr, dialaddr);
	listening := make(chan string);
	done := make(chan int);
	if network == "udp" {
		listenaddr += ":0"	// any available port
	}
	go runPacket(t, network, listenaddr, listening, done);
	addr := <-listening;	// wait for server to start
	if network == "udp" {
		dialaddr += addr[strings.LastIndex(addr, ":"):len(addr)]
	}
	connect(t, network, dialaddr);
	<-done;	// tell server to stop
	<-done;	// wait for stop
}

func TestUDPServer(t *testing.T) {
	doTestPacket(t, "udp", "0.0.0.0", "127.0.0.1");
	doTestPacket(t, "udp", "[::]", "[::ffff:127.0.0.1]");
	doTestPacket(t, "udp", "[::]", "127.0.0.1");
	doTestPacket(t, "udp", "", "127.0.0.1");
	doTestPacket(t, "udp", "0.0.0.0", "[::ffff:127.0.0.1]");
}

func TestUnixDatagramServer(t *testing.T) {
	os.Remove("/tmp/gotest1.net");
	os.Remove("/tmp/gotest1.net.local");
	doTestPacket(t, "unixgram", "/tmp/gotest1.net", "/tmp/gotest1.net");
	os.Remove("/tmp/gotest1.net");
	os.Remove("/tmp/gotest1.net.local");
	if syscall.OS == "linux" {
		// Test abstract unix domain socket, a Linux-ism
		doTestPacket(t, "unixgram", "@gotest1/net", "@gotest1/net")
	}
}
<commit_msg>net: disable more ipv6 tests<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package net

import (
	"io";
	"os";
	"strings";
	"syscall";
	"testing";
)

func runEcho(fd io.ReadWriter, done chan<- int) {
	var buf [1024]byte;

	for {
		n, err := fd.Read(&buf);
		if err != nil || n == 0 {
			break
		}
		fd.Write(buf[0:n]);
	}
	done <- 1;
}

func runServe(t *testing.T, network, addr string, listening chan<- string, done chan<- int) {
	l, err := Listen(network, addr);
	if err != nil {
		t.Fatalf("net.Listen(%q, %q) = _, %v", network, addr, err)
	}
	listening <- l.Addr().String();

	for {
		fd, err := l.Accept();
		if err != nil {
			break
		}
		echodone := make(chan int);
		go runEcho(fd, echodone);
		<-echodone;	// make sure Echo stops
		l.Close();
	}
	done <- 1;
}

func connect(t *testing.T, network, addr string) {
	var laddr string;
	if network == "unixgram" {
		laddr = addr + ".local"
	}
	fd, err := Dial(network, laddr, addr);
	if err != nil {
		t.Fatalf("net.Dial(%q, %q, %q) = _, %v", network, laddr, addr, err)
	}

	b := strings.Bytes("hello, world\n");
	var b1 [100]byte;

	n, errno := fd.Write(b);
	if n != len(b) {
		t.Fatalf("fd.Write(%q) = %d, %v", b, n, errno)
	}

	n, errno = fd.Read(&b1);
	if n != len(b) {
		t.Fatalf("fd.Read() = %d, %v", n, errno)
	}
	fd.Close();
}

func doTest(t *testing.T, network, listenaddr, dialaddr string) {
	t.Logf("Test %s %s %s\n", network, listenaddr, dialaddr);
	listening := make(chan string);
	done := make(chan int);
	if network == "tcp" {
		listenaddr += ":0"	// any available port
	}
	go runServe(t, network, listenaddr, listening, done);
	addr := <-listening;	// wait for server to start
	if network == "tcp" {
		dialaddr += addr[strings.LastIndex(addr, ":"):len(addr)]
	}
	connect(t, network, dialaddr);
	<-done;	// make sure server stopped
}

func TestTCPServer(t *testing.T) {
	doTest(t, "tcp", "0.0.0.0", "127.0.0.1");
	doTest(t, "tcp", "", "127.0.0.1");
	if kernelSupportsIPv6() {
		doTest(t, "tcp", "[::]", "[::ffff:127.0.0.1]");
		doTest(t, "tcp", "[::]", "127.0.0.1");
		doTest(t, "tcp", "0.0.0.0", "[::ffff:127.0.0.1]");
	}
}

func TestUnixServer(t *testing.T) {
	os.Remove("/tmp/gotest.net");
	doTest(t, "unix", "/tmp/gotest.net", "/tmp/gotest.net");
	os.Remove("/tmp/gotest.net");
	if syscall.OS == "linux" {
		// Test abstract unix domain socket, a Linux-ism
		doTest(t, "unix", "@gotest/net", "@gotest/net")
	}
}

func runPacket(t *testing.T, network, addr string, listening chan<- string, done chan<- int) {
	c, err := ListenPacket(network, addr);
	if err != nil {
		t.Fatalf("net.ListenPacket(%q, %q) = _, %v", network, addr, err)
	}
	listening <- c.LocalAddr().String();
	c.SetReadTimeout(10e6);	// 10ms
	var buf [1000]byte;
	for {
		n, addr, err := c.ReadFrom(&buf);
		if err == os.EAGAIN {
			if done <- 1 {
				break
			}
			continue;
		}
		if err != nil {
			break
		}
		if _, err = c.WriteTo(buf[0:n], addr); err != nil {
			t.Fatalf("WriteTo %v: %v", addr, err)
		}
	}
	c.Close();
	done <- 1;
}

func doTestPacket(t *testing.T, network, listenaddr, dialaddr string) {
	t.Logf("TestPacket %s %s %s\n", network, listenaddr, dialaddr);
	listening := make(chan string);
	done := make(chan int);
	if network == "udp" {
		listenaddr += ":0"	// any available port
	}
	go runPacket(t, network, listenaddr, listening, done);
	addr := <-listening;	// wait for server to start
	if network == "udp" {
		dialaddr += addr[strings.LastIndex(addr, ":"):len(addr)]
	}
	connect(t, network, dialaddr);
	<-done;	// tell server to stop
	<-done;	// wait for stop
}

func TestUDPServer(t *testing.T) {
	doTestPacket(t, "udp", "0.0.0.0", "127.0.0.1");
	doTestPacket(t, "udp", "", "127.0.0.1");
	if kernelSupportsIPv6() {
		doTestPacket(t, "udp", "[::]", "[::ffff:127.0.0.1]");
		doTestPacket(t, "udp", "[::]", "127.0.0.1");
		doTestPacket(t, "udp", "0.0.0.0", "[::ffff:127.0.0.1]");
	}
}

func TestUnixDatagramServer(t *testing.T) {
	os.Remove("/tmp/gotest1.net");
	os.Remove("/tmp/gotest1.net.local");
	doTestPacket(t, "unixgram", "/tmp/gotest1.net", "/tmp/gotest1.net");
	os.Remove("/tmp/gotest1.net");
	os.Remove("/tmp/gotest1.net.local");
	if syscall.OS == "linux" {
		// Test abstract unix domain socket, a Linux-ism
		doTestPacket(t, "unixgram", "@gotest1/net", "@gotest1/net")
	}
}
<|endoftext|>


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

// +build darwin dragonfly freebsd nacl netbsd openbsd

package net

import (
	"os"
	"runtime"
	"syscall"
)

func setDefaultSockopts(s, family, sotype int, ipv6only bool) error {
	if runtime.GOOS == "dragonfly" && sotype != syscall.SOCK_RAW {
		// On DragonFly BSD, we adjust the ephemeral port
		// range because unlike other BSD systems its default
		// port range doesn't conform to IANA recommendation
		// as described in RFC 6355 and is pretty narrow.
		switch family {
		case syscall.AF_INET:
			syscall.SetsockoptInt(s, syscall.IPPROTO_IP, syscall.IP_PORTRANGE, syscall.IP_PORTRANGE_HIGH)
		case syscall.AF_INET6:
			syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_PORTRANGE, syscall.IPV6_PORTRANGE_HIGH)
		}
	}
	if family == syscall.AF_INET6 && sotype != syscall.SOCK_RAW {
		// Allow both IP versions even if the OS default
		// is otherwise.  Note that some operating systems
		// never admit this option.
		syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, boolint(ipv6only))
	}
	// Allow broadcast.
	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1))
}

func setDefaultListenerSockopts(s int) error {
	// Allow reuse of recently-used addresses.
	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1))
}

func setDefaultMulticastSockopts(s int) error {
	// Allow multicast UDP and raw IP datagram sockets to listen
	// concurrently across multiple listeners.
	if err := syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil {
		return os.NewSyscallError("setsockopt", err)
	}
	// Allow reuse of recently-used ports.
	// This option is supported only in descendants of 4.4BSD,
	// to make an effective multicast application that requires
	// quick draw possible.
	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEPORT, 1))
}
<commit_msg>net: fix typo<commit_after>// Copyright 2011 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build darwin dragonfly freebsd nacl netbsd openbsd

package net

import (
	"os"
	"runtime"
	"syscall"
)

func setDefaultSockopts(s, family, sotype int, ipv6only bool) error {
	if runtime.GOOS == "dragonfly" && sotype != syscall.SOCK_RAW {
		// On DragonFly BSD, we adjust the ephemeral port
		// range because unlike other BSD systems its default
		// port range doesn't conform to IANA recommendation
		// as described in RFC 6056 and is pretty narrow.
		switch family {
		case syscall.AF_INET:
			syscall.SetsockoptInt(s, syscall.IPPROTO_IP, syscall.IP_PORTRANGE, syscall.IP_PORTRANGE_HIGH)
		case syscall.AF_INET6:
			syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_PORTRANGE, syscall.IPV6_PORTRANGE_HIGH)
		}
	}
	if family == syscall.AF_INET6 && sotype != syscall.SOCK_RAW {
		// Allow both IP versions even if the OS default
		// is otherwise.  Note that some operating systems
		// never admit this option.
		syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, boolint(ipv6only))
	}
	// Allow broadcast.
	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1))
}

func setDefaultListenerSockopts(s int) error {
	// Allow reuse of recently-used addresses.
	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1))
}

func setDefaultMulticastSockopts(s int) error {
	// Allow multicast UDP and raw IP datagram sockets to listen
	// concurrently across multiple listeners.
	if err := syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil {
		return os.NewSyscallError("setsockopt", err)
	}
	// Allow reuse of recently-used ports.
	// This option is supported only in descendants of 4.4BSD,
	// to make an effective multicast application that requires
	// quick draw possible.
	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEPORT, 1))
}
<|endoftext|>