<commit_before>package service

import (
	"bytes"
	"context"
	"fmt"
	"io/ioutil"
	"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/util/wait"
	"k8s.io/client-go/kubernetes/scheme"
	"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 || infra.Status.PlatformStatus.Type == configv1.KubevirtPlatformType || infra.Status.PlatformStatus.Type == configv1.LibvirtPlatformType {
		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)
	url := fmt.Sprintf("http://%s/echo?msg=Hello", net.JoinHostPort(tcpIngressIP, strconv.Itoa(svcPort)))
	// this client reuses connections and detects abrupt breaks
	continuousClient := &http.Client{
		Timeout: 10 * time.Second,
		Transport: &http.Transport{
			Dial: (&net.Dialer{
				Timeout: 15 * time.Second,
			}).Dial,
			TLSHandshakeTimeout: 15 * time.Second,
		},
	}

	m.AddSampler(
		monitor.StartSampling(ctx, m, time.Second, func(previous bool) (condition *monitor.Condition, next bool) {
			resp, err := continuousClient.Get(url)
			if err == nil {
				defer resp.Body.Close()
				body, err := ioutil.ReadAll(resp.Body)
				if err == nil && !bytes.Contains(body, []byte("Hello")) {
					err = fmt.Errorf("service returned success but did not contain the correct body contents: %q", string(body))
				}
			}
			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 := &http.Client{
		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,
		},
	}
	m.AddSampler(
		monitor.StartSampling(ctx, m, time.Second, func(previous bool) (condition *monitor.Condition, next bool) {
			resp, err := client.Get(url)
			if err == nil {
				defer resp.Body.Close()
				body, err := ioutil.ReadAll(resp.Body)
				if err == nil && !bytes.Contains(body, []byte("Hello")) {
					err = fmt.Errorf("service returned success but did not contain the correct body contents: %q", string(body))
				}
			}
			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>test: add vsphere to unsupported platforms for LB service<commit_after>package service

import (
	"bytes"
	"context"
	"fmt"
	"io/ioutil"
	"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/util/wait"
	"k8s.io/client-go/kubernetes/scheme"
	"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 || infra.Status.PlatformStatus.Type == configv1.KubevirtPlatformType || infra.Status.PlatformStatus.Type == configv1.LibvirtPlatformType || infra.Status.PlatformStatus.Type == configv1.VSpherePlatformType {
		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)
	url := fmt.Sprintf("http://%s/echo?msg=Hello", net.JoinHostPort(tcpIngressIP, strconv.Itoa(svcPort)))
	// this client reuses connections and detects abrupt breaks
	continuousClient := &http.Client{
		Timeout: 10 * time.Second,
		Transport: &http.Transport{
			Dial: (&net.Dialer{
				Timeout: 15 * time.Second,
			}).Dial,
			TLSHandshakeTimeout: 15 * time.Second,
		},
	}

	m.AddSampler(
		monitor.StartSampling(ctx, m, time.Second, func(previous bool) (condition *monitor.Condition, next bool) {
			resp, err := continuousClient.Get(url)
			if err == nil {
				defer resp.Body.Close()
				body, err := ioutil.ReadAll(resp.Body)
				if err == nil && !bytes.Contains(body, []byte("Hello")) {
					err = fmt.Errorf("service returned success but did not contain the correct body contents: %q", string(body))
				}
			}
			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 := &http.Client{
		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,
		},
	}
	m.AddSampler(
		monitor.StartSampling(ctx, m, time.Second, func(previous bool) (condition *monitor.Condition, next bool) {
			resp, err := client.Get(url)
			if err == nil {
				defer resp.Body.Close()
				body, err := ioutil.ReadAll(resp.Body)
				if err == nil && !bytes.Contains(body, []byte("Hello")) {
					err = fmt.Errorf("service returned success but did not contain the correct body contents: %q", string(body))
				}
			}
			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 operation

const Version string = "0.1.4"
<commit_msg>bump version to 0.1.5<commit_after>package operation

const Version string = "0.1.5"
<|endoftext|>


<commit_before>package ov

import (
	"encoding/json"
	"fmt"
	"github.com/HewlettPackard/oneview-golang/rest"
	"github.com/HewlettPackard/oneview-golang/utils"
	"github.com/docker/machine/libmachine/log"
)

// The Marshal() will omit the bool attibutes below if they are false.
// Please remove the omitempty option and use it as and when required.

type StorageVolume struct {
	Category                  string                    `json:"category,omitempty"`
	Created                   string                    `json:"created,omitempty"`
	Description               utils.Nstring             `json:"description,omitempty"`
	ETAG                      string                    `json:"eTag,omitempty"`
	Name                      string                    `json:"name,omitempty"`
	State                     string                    `json:"state,omitempty"`
	Status                    string                    `json:"status,omitempty"`
	Type                      string                    `json:"type,omitempty"`
	URI                       utils.Nstring             `json:"uri,omitempty"`
	DeviceVolumeName          string                    `json:"deviceVolumeName,omitempty"`
	RequestingRefresh         bool                      `json:"requestingRefresh,omitempty"`
	AllocatedCapacity         string                    `json:"allocatedCapacity,omitempty"`
	InitialScopeUris          []utils.Nstring           `json:"initialScopeUris,omitempty"`
	DeviceSpecificAttributes  *DeviceSpecificAttributes `json:"deviceSpecificAttributes,omitempty"`
	VolumeTemplateUri         utils.Nstring             `json:"volumeTemplateUri,omitempty"`
	IsShareable               *bool                     `json:"isShareable,omitempty"`
	StoragePoolUri            utils.Nstring             `json:"storagePoolUri,omitempty"`
	StorageSystemUri          utils.Nstring             `json:"storageSystemUri,omitempty"`
	ProvisionedCapacity       string                    `json:"provisionedCapacity,omitempty"`
	Properties                *Properties               `json:"properties,omitempty"`
	TemplateURI               utils.Nstring             `json:"templateURI,omitempty"`
	IsPermanent               *bool                     `json:"isPermanent,omitempty"`
	ProvisioningTypeForUpdate string                    `json:"provisioningType,omitempty"`
	TemplateVersion           string                    `json:"templateVersion,omitempty"`
	//	Wwn										string				`json:""`

	/*
	   Category              string        `json:"category,omitempty"`              //  "type": "StorageVolume",
	   Created               string        `json:"created,omitempty"`               //  "created": "2016-06-20T22:48:14.422Z"
	   Description           string        `json:"description,omitempty"`           //  "description": "Integration test volume 2",
	   ETAG                  string        `json:"eTag,omitempty"`                  //  "eTag": "2016-06-20T22:48:17.704Z",            string        `json:"modified,omitempty"`              // "modified": "20150831T154835.250Z",
	   Name                  string        `json:"name,omitempty"`                  //  "name": "Volume_2",
	   State                 string        `json:"state,omitempty"`                 //  "state": "Configured",
	   Status                string        `json:"status,omitempty"`                //  "status": "OK",
	   Type                  string        `json:"type,omitempty"`                  //  "type": "StorageVolume",
	   URI                   utils.Nstring `json:"uri,omitempty"`                   //  "uri": "/rest/storage-volumes/527801AC-B6B6-4A63-8510-D32906C9C57B"
	   Shareable							string				`json:"shareable,omitempty"`                                //  "shareable": false,
	   AllocatedCapacity			string				`json:""`																 //  "allocatedCapacity": "1073741824",
	   DeviceType						string				`json:""`																 //  "deviceType": "SSD",
	   DeviceVolumeName			string				`json:""`                                //  "deviceVolumeName": "Volume_2",
	   IsPermanent						string 				`json:""`                                //  "isPermanent": true,
	   RaidLevel							string				`json:""`                								 //  "raidLevel": "RAID5",
	   RefreshState					string				`json:""`                                //  "refreshState": "NotRefreshing",
	   RevertToSnapshotUri		string				`json:""`                                //  "revertToSnapshotUri": null,
	   SnapshotPoolUri				string				`json:""`                                //  "snapshotPoolUri": "/rest/storage-pools/000D692C-74B3-44AC-B297-3741AABE29F8",
	   Snapshots							string				`json:""`                                //  "snapshots": null,
	   StateReason						string				`json:""`                                //  "stateReason": "None",
	   StoragePoolUri				string				`json:"storagePoolUri,omitempty"`        //  "storagePoolUri": "/rest/storage-pools/000D692C-74B3-44AC-B297-3741AABE29F8",
	   StorageSystemUri			string				`json:"storageSystemUri,omitempty"`      //  "storageSystemUri": "/rest/storage-systems/TXQ1000307",
	   ProvisionType					string 				`json:"provisionType,omitempty"`         //  "provisionType": "Full",
	   ProvisionedCapacity		string				`json:"provisionedCapacity,omitempty"`   //  "provisionedCapacity": "1073741824",
	   ProvisioningParameters []ProvisioningParameters		`json:"provisioningParameters,omitempty"`
	   //	Wwn										string				`json:""`                                //  "wwn": "DC:57:93:56:32:00:10:00:30:71:46:64:62:89:52:11",

	*/
}

type ProvisioningParameters struct {
	StoragePoolUri    utils.Nstring `json:"storagePoolUri,omitempty"`
	ProvisionType     string        `json:"provisionType,omitempty"`
	RequestedCapacity string        `json:"requestedCapacity,omitempty"`
	Shareable         bool          `json:"shareable,omitempty"`
}

type Properties struct {
	Name                string        `json:"name,omitempty"`
	Storagepool         utils.Nstring `json:"storagePool,omitempty"`
	Size                int           `json:"size,omitempty"`
	ProvisioningType    string        `json:"provisioningType,omitempty"`
	DataTransferLimit   int           `json:"dataTransferLimit,omitempty"`
	IsDeduplicated      *bool         `json:"isDeduplicated,omitempty"`
	IsEncrypted         *bool         `json:"isEncrypted,omitempty"`
	IsPinned            *bool         `json:"isPinned,omitempty"`
	IsCompressed        *bool         `json:"isCompressed,omitempty"`
	IsShareable         *bool         `json:"isShareable,omitempty"`
	DataProtectionLevel string        `json:"dataProtectionLevel,omitempty"`
}

type DeviceSpecificAttributes struct {
	ApplicationCategory           string        `json:"applicationCategory,omitempty"`
	BlockSize                     int           `json:"blockSize,omitempty"`
	DataTransferLimit             int           `json:"dataTransferLimit,omitempty"`
	FolderId                      string        `json:"folderId,omitempty"`
	FolderName                    string        `json:"folderName,omitempty"`
	IopsLimit                     int           `json:"iopsLimit,omitempty"`
	IsDeduplicated                bool          `json:"isDeduplicated,omitempty"`
	IsEncrypted                   bool          `json:"isEncrypted,omitempty"`
	IsPinned                      bool          `json:"isPinned,omitempty"`
	PreviouslyDeduplicated        bool          `json:"previouslyDeduplicated,omitempty"`
	IsCompressed                  bool          `json:"isCompressed,omitempty"`
	Transport                     string        `json:"transport,omitempty"`
	Iqn                           string        `json:"iqn,omitempty"`
	NumberOfReplicas              int           `json:"numberOfReplicas,omitempty"`
	DataProtectionLevel           string        `json:"dataProtectionLevel,omitempty"`
	Id                            int           `json:"id,omitempty"`
	Uri                           utils.Nstring `json:"uri,omitempty"`
	CopyState                     string        `json:"copyState,omitempty"`
	SnapshotPoolUri               utils.Nstring `json:"snapshotPoolUri,omitempty"`
	IsAdaptiveOptimizationEnabled bool          `json:"isAdaptiveOptimizationEnabled,omitempty"`
}

type StorageVolumesList struct {
	Total       int             `json:"total,omitempty"`       // "total": 1,
	Count       int             `json:"count,omitempty"`       // "count": 1,
	Start       int             `json:"start,omitempty"`       // "start": 0,
	PrevPageURI utils.Nstring   `json:"prevPageUri,omitempty"` // "prevPageUri": null,
	NextPageURI utils.Nstring   `json:"nextPageUri,omitempty"` // "nextPageUri": null,
	URI         utils.Nstring   `json:"uri,omitempty"`         // "uri": "/rest/server-profiles?filter=connectionTemplateUri%20matches%7769cae0-b680-435b-9b87-9b864c81657fsort=name:asc"
	Members     []StorageVolume `json:"members,omitempty"`     // "members":[]
}

func (c *OVClient) GetStorageVolumeByName(name string) (StorageVolume, error) {
	var (
		sVol StorageVolume
	)
	sVols, err := c.GetStorageVolumes(fmt.Sprintf("name matches '%s'", name), "name:asc")
	if sVols.Total > 0 {
		return sVols.Members[0], err
	} else {
		return sVol, err
	}
}

func (c *OVClient) GetStorageVolumes(filter string, sort string) (StorageVolumesList, error) {
	var (
		uri   = "/rest/storage-volumes"
		q     map[string]interface{}
		sVols StorageVolumesList
	)
	q = make(map[string]interface{})
	if len(filter) > 0 {
		q["filter"] = filter
	}

	if sort != "" {
		q["sort"] = sort
	}

	// refresh login
	c.RefreshLogin()
	c.SetAuthHeaderOptions(c.GetAuthHeaderMap())
	// Setup query
	if len(q) > 0 {
		c.SetQueryString(q)
	}

	data, err := c.RestAPICall(rest.GET, uri, nil)
	if err != nil {
		return sVols, err
	}

	log.Debugf("GetStorageVolumes %s", data)
	if err := json.Unmarshal([]byte(data), &sVols); err != nil {
		return sVols, err
	}
	return sVols, nil
}

func (c *OVClient) CreateStorageVolume(sVol StorageVolume) error {
	log.Infof("Initializing creation of storage volume for %s.", sVol.Name)
	var (
		uri = "/rest/storage-volumes"
		t   *Task
	)
	// refresh login
	c.RefreshLogin()
	c.SetAuthHeaderOptions(c.GetAuthHeaderMap())

	t = t.NewProfileTask(c)
	t.ResetTask()
	log.Debugf("REST : %s \n %+v\n", uri, sVol)
	log.Debugf("task -> %+v", t)

	data, err := c.RestAPICall(rest.POST, uri, sVol)
	if err != nil {
		t.TaskIsDone = true
		log.Errorf("Error submitting new storage volume request: %s", err)
		return err
	}

	log.Debugf("Response New StorageVolume %s", data)
	if err := json.Unmarshal([]byte(data), &t); err != nil {
		t.TaskIsDone = true
		log.Errorf("Error with task un-marshal: %s", err)
		return err
	}

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

	return nil
}

func (c *OVClient) DeleteStorageVolume(name string) error {
	var (
		sVol StorageVolume
		err  error
		t    *Task
		uri  string
	)

	sVol, err = c.GetStorageVolumeByName(name)
	if err != nil {
		return err
	}
	if sVol.Name != "" {
		t = t.NewProfileTask(c)
		t.ResetTask()
		log.Debugf("REST : %s \n %+v\n", sVol.URI, sVol)
		log.Debugf("task -> %+v", t)
		uri = sVol.URI.String()
		if uri == "" {
			log.Warn("Unable to post delete, no uri found.")
			t.TaskIsDone = true
			return err
		}
		data, err := c.RestAPICall(rest.DELETE, uri, nil)
		if err != nil {
			log.Errorf("Error submitting delete storage volume request: %s", err)
			t.TaskIsDone = true
			return err
		}

		log.Debugf("Response delete storage volume %s", data)
		if err := json.Unmarshal([]byte(data), &t); err != nil {
			t.TaskIsDone = true
			log.Errorf("Error with task un-marshal: %s", err)
			return err
		}
		err = t.Wait()
		if err != nil {
			return err
		}
		return nil
	} else {
		log.Infof("StorageVolume could not be found to delete, %s, skipping delete ...", name)
	}
	return nil
}

func (c *OVClient) UpdateStorageVolume(sVol StorageVolume) error {
	log.Infof("Initializing update of storage volume for %s.", sVol.Name)
	var (
		uri = sVol.URI.String()
		t   *Task
	)
	// refresh login
	c.RefreshLogin()
	c.SetAuthHeaderOptions(c.GetAuthHeaderMap())

	t = t.NewProfileTask(c)
	t.ResetTask()
	log.Debugf("REST : %s \n %+v\n", uri, sVol)
	log.Debugf("task -> %+v", t)
	data, err := c.RestAPICall(rest.PUT, uri, sVol)
	if err != nil {
		t.TaskIsDone = true
		log.Errorf("Error submitting update StorageVolume request: %s", err)
		return err
	}
	log.Debugf("Response update StorageVolume %s", data)
	if err := json.Unmarshal([]byte(data), &t); err != nil {
		t.TaskIsDone = true
		log.Errorf("Error with task un-marshal: %s", err)
		return err
	}

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

	return nil
}
<commit_msg>Storage volume field fix.<commit_after>package ov

import (
	"encoding/json"
	"fmt"
	"github.com/HewlettPackard/oneview-golang/rest"
	"github.com/HewlettPackard/oneview-golang/utils"
	"github.com/docker/machine/libmachine/log"
)

// The Marshal() will omit the bool attibutes below if they are false.
// Please remove the omitempty option and use it as and when required.

type StorageVolume struct {
	Category                  string                    `json:"category,omitempty"`
	Created                   string                    `json:"created,omitempty"`
	Description               utils.Nstring             `json:"description,omitempty"`
	ETAG                      string                    `json:"eTag,omitempty"`
	Name                      string                    `json:"name,omitempty"`
	State                     string                    `json:"state,omitempty"`
	Status                    string                    `json:"status,omitempty"`
	Type                      string                    `json:"type,omitempty"`
	URI                       utils.Nstring             `json:"uri,omitempty"`
	DeviceVolumeName          string                    `json:"deviceVolumeName,omitempty"`
	RequestingRefresh         bool                      `json:"requestingRefresh,omitempty"`
	AllocatedCapacity         string                    `json:"allocatedCapacity,omitempty"`
	InitialScopeUris          []utils.Nstring           `json:"initialScopeUris,omitempty"`
	DeviceSpecificAttributes  *DeviceSpecificAttributes `json:"deviceSpecificAttributes,omitempty"`
	VolumeTemplateUri         utils.Nstring             `json:"volumeTemplateUri,omitempty"`
	IsShareable               *bool                     `json:"isShareable,omitempty"`
	StoragePoolUri            utils.Nstring             `json:"storagePoolUri,omitempty"`
	StorageSystemUri          utils.Nstring             `json:"storageSystemUri,omitempty"`
	ProvisionedCapacity       string                    `json:"provisionedCapacity,omitempty"`
	Properties                *Properties               `json:"properties,omitempty"`
	TemplateURI               utils.Nstring             `json:"templateURI,omitempty"`
	IsPermanent               *bool                     `json:"isPermanent,omitempty"`
	ProvisioningTypeForUpdate string                    `json:"provisioningType,omitempty"`
	TemplateVersion           string                    `json:"templateVersion,omitempty"`
	//	Wwn										string				`json:""`

	/*
	   Category              string        `json:"category,omitempty"`              //  "type": "StorageVolume",
	   Created               string        `json:"created,omitempty"`               //  "created": "2016-06-20T22:48:14.422Z"
	   Description           string        `json:"description,omitempty"`           //  "description": "Integration test volume 2",
	   ETAG                  string        `json:"eTag,omitempty"`                  //  "eTag": "2016-06-20T22:48:17.704Z",            string        `json:"modified,omitempty"`              // "modified": "20150831T154835.250Z",
	   Name                  string        `json:"name,omitempty"`                  //  "name": "Volume_2",
	   State                 string        `json:"state,omitempty"`                 //  "state": "Configured",
	   Status                string        `json:"status,omitempty"`                //  "status": "OK",
	   Type                  string        `json:"type,omitempty"`                  //  "type": "StorageVolume",
	   URI                   utils.Nstring `json:"uri,omitempty"`                   //  "uri": "/rest/storage-volumes/527801AC-B6B6-4A63-8510-D32906C9C57B"
	   Shareable							string				`json:"shareable,omitempty"`                                //  "shareable": false,
	   AllocatedCapacity			string				`json:""`																 //  "allocatedCapacity": "1073741824",
	   DeviceType						string				`json:""`																 //  "deviceType": "SSD",
	   DeviceVolumeName			string				`json:""`                                //  "deviceVolumeName": "Volume_2",
	   IsPermanent						string 				`json:""`                                //  "isPermanent": true,
	   RaidLevel							string				`json:""`                								 //  "raidLevel": "RAID5",
	   RefreshState					string				`json:""`                                //  "refreshState": "NotRefreshing",
	   RevertToSnapshotUri		string				`json:""`                                //  "revertToSnapshotUri": null,
	   SnapshotPoolUri				string				`json:""`                                //  "snapshotPoolUri": "/rest/storage-pools/000D692C-74B3-44AC-B297-3741AABE29F8",
	   Snapshots							string				`json:""`                                //  "snapshots": null,
	   StateReason						string				`json:""`                                //  "stateReason": "None",
	   StoragePoolUri				string				`json:"storagePoolUri,omitempty"`        //  "storagePoolUri": "/rest/storage-pools/000D692C-74B3-44AC-B297-3741AABE29F8",
	   StorageSystemUri			string				`json:"storageSystemUri,omitempty"`      //  "storageSystemUri": "/rest/storage-systems/TXQ1000307",
	   ProvisionType					string 				`json:"provisionType,omitempty"`         //  "provisionType": "Full",
	   ProvisionedCapacity		string				`json:"provisionedCapacity,omitempty"`   //  "provisionedCapacity": "1073741824",
	   ProvisioningParameters []ProvisioningParameters		`json:"provisioningParameters,omitempty"`
	   //	Wwn										string				`json:""`                                //  "wwn": "DC:57:93:56:32:00:10:00:30:71:46:64:62:89:52:11",

	*/
}

type ProvisioningParameters struct {
	StoragePoolUri    utils.Nstring `json:"storagePoolUri,omitempty"`
	ProvisionType     string        `json:"provisionType,omitempty"`
	RequestedCapacity string        `json:"requestedCapacity,omitempty"`
	Shareable         bool          `json:"shareable,omitempty"`
}

type Properties struct {
	Name                string        `json:"name,omitempty"`
	Storagepool         utils.Nstring `json:"storagePool,omitempty"`
	Size                int           `json:"size,omitempty"`
	ProvisioningType    string        `json:"provisioningType,omitempty"`
	DataTransferLimit   int           `json:"dataTransferLimit,omitempty"`
	IsDeduplicated      bool          `json:"isDeduplicated,omitempty"`
	IsEncrypted         bool          `json:"isEncrypted,omitempty"`
	IsPinned            bool          `json:"isPinned,omitempty"`
	IsCompressed        bool          `json:"isCompressed,omitempty"`
	IsShareable         bool          `json:"isShareable,omitempty"`
	DataProtectionLevel string        `json:"dataProtectionLevel,omitempty"`
}

type DeviceSpecificAttributes struct {
	ApplicationCategory           string        `json:"applicationCategory,omitempty"`
	BlockSize                     int           `json:"blockSize,omitempty"`
	DataTransferLimit             int           `json:"dataTransferLimit,omitempty"`
	FolderId                      string        `json:"folderId,omitempty"`
	FolderName                    string        `json:"folderName,omitempty"`
	IopsLimit                     int           `json:"iopsLimit,omitempty"`
	IsDeduplicated                bool          `json:"isDeduplicated,omitempty"`
	IsEncrypted                   bool          `json:"isEncrypted,omitempty"`
	IsPinned                      bool          `json:"isPinned,omitempty"`
	PreviouslyDeduplicated        bool          `json:"previouslyDeduplicated,omitempty"`
	IsCompressed                  bool          `json:"isCompressed,omitempty"`
	Transport                     string        `json:"transport,omitempty"`
	Iqn                           string        `json:"iqn,omitempty"`
	NumberOfReplicas              int           `json:"numberOfReplicas,omitempty"`
	DataProtectionLevel           string        `json:"dataProtectionLevel,omitempty"`
	Id                            int           `json:"id,omitempty"`
	Uri                           utils.Nstring `json:"uri,omitempty"`
	CopyState                     string        `json:"copyState,omitempty"`
	SnapshotPoolUri               utils.Nstring `json:"snapshotPoolUri,omitempty"`
	IsAdaptiveOptimizationEnabled bool          `json:"isAdaptiveOptimizationEnabled,omitempty"`
}

type StorageVolumesList struct {
	Total       int             `json:"total,omitempty"`       // "total": 1,
	Count       int             `json:"count,omitempty"`       // "count": 1,
	Start       int             `json:"start,omitempty"`       // "start": 0,
	PrevPageURI utils.Nstring   `json:"prevPageUri,omitempty"` // "prevPageUri": null,
	NextPageURI utils.Nstring   `json:"nextPageUri,omitempty"` // "nextPageUri": null,
	URI         utils.Nstring   `json:"uri,omitempty"`         // "uri": "/rest/server-profiles?filter=connectionTemplateUri%20matches%7769cae0-b680-435b-9b87-9b864c81657fsort=name:asc"
	Members     []StorageVolume `json:"members,omitempty"`     // "members":[]
}

func (c *OVClient) GetStorageVolumeByName(name string) (StorageVolume, error) {
	var (
		sVol StorageVolume
	)
	sVols, err := c.GetStorageVolumes(fmt.Sprintf("name matches '%s'", name), "name:asc")
	if sVols.Total > 0 {
		return sVols.Members[0], err
	} else {
		return sVol, err
	}
}

func (c *OVClient) GetStorageVolumes(filter string, sort string) (StorageVolumesList, error) {
	var (
		uri   = "/rest/storage-volumes"
		q     map[string]interface{}
		sVols StorageVolumesList
	)
	q = make(map[string]interface{})
	if len(filter) > 0 {
		q["filter"] = filter
	}

	if sort != "" {
		q["sort"] = sort
	}

	// refresh login
	c.RefreshLogin()
	c.SetAuthHeaderOptions(c.GetAuthHeaderMap())
	// Setup query
	if len(q) > 0 {
		c.SetQueryString(q)
	}

	data, err := c.RestAPICall(rest.GET, uri, nil)
	if err != nil {
		return sVols, err
	}

	log.Debugf("GetStorageVolumes %s", data)
	if err := json.Unmarshal([]byte(data), &sVols); err != nil {
		return sVols, err
	}
	return sVols, nil
}

func (c *OVClient) CreateStorageVolume(sVol StorageVolume) error {
	log.Infof("Initializing creation of storage volume for %s.", sVol.Name)
	var (
		uri = "/rest/storage-volumes"
		t   *Task
	)
	// refresh login
	c.RefreshLogin()
	c.SetAuthHeaderOptions(c.GetAuthHeaderMap())

	t = t.NewProfileTask(c)
	t.ResetTask()
	log.Debugf("REST : %s \n %+v\n", uri, sVol)
	log.Debugf("task -> %+v", t)

	data, err := c.RestAPICall(rest.POST, uri, sVol)
	if err != nil {
		t.TaskIsDone = true
		log.Errorf("Error submitting new storage volume request: %s", err)
		return err
	}

	log.Debugf("Response New StorageVolume %s", data)
	if err := json.Unmarshal([]byte(data), &t); err != nil {
		t.TaskIsDone = true
		log.Errorf("Error with task un-marshal: %s", err)
		return err
	}

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

	return nil
}

func (c *OVClient) DeleteStorageVolume(name string) error {
	var (
		sVol StorageVolume
		err  error
		t    *Task
		uri  string
	)

	sVol, err = c.GetStorageVolumeByName(name)
	if err != nil {
		return err
	}
	if sVol.Name != "" {
		t = t.NewProfileTask(c)
		t.ResetTask()
		log.Debugf("REST : %s \n %+v\n", sVol.URI, sVol)
		log.Debugf("task -> %+v", t)
		uri = sVol.URI.String()
		if uri == "" {
			log.Warn("Unable to post delete, no uri found.")
			t.TaskIsDone = true
			return err
		}
		data, err := c.RestAPICall(rest.DELETE, uri, nil)
		if err != nil {
			log.Errorf("Error submitting delete storage volume request: %s", err)
			t.TaskIsDone = true
			return err
		}

		log.Debugf("Response delete storage volume %s", data)
		if err := json.Unmarshal([]byte(data), &t); err != nil {
			t.TaskIsDone = true
			log.Errorf("Error with task un-marshal: %s", err)
			return err
		}
		err = t.Wait()
		if err != nil {
			return err
		}
		return nil
	} else {
		log.Infof("StorageVolume could not be found to delete, %s, skipping delete ...", name)
	}
	return nil
}

func (c *OVClient) UpdateStorageVolume(sVol StorageVolume) error {
	log.Infof("Initializing update of storage volume for %s.", sVol.Name)
	var (
		uri = sVol.URI.String()
		t   *Task
	)
	// refresh login
	c.RefreshLogin()
	c.SetAuthHeaderOptions(c.GetAuthHeaderMap())

	t = t.NewProfileTask(c)
	t.ResetTask()
	log.Debugf("REST : %s \n %+v\n", uri, sVol)
	log.Debugf("task -> %+v", t)
	data, err := c.RestAPICall(rest.PUT, uri, sVol)
	if err != nil {
		t.TaskIsDone = true
		log.Errorf("Error submitting update StorageVolume request: %s", err)
		return err
	}
	log.Debugf("Response update StorageVolume %s", data)
	if err := json.Unmarshal([]byte(data), &t); err != nil {
		t.TaskIsDone = true
		log.Errorf("Error with task un-marshal: %s", err)
		return err
	}

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

	return nil
}
<|endoftext|>


<commit_before>package server

import (
	"bytes"
	"context"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/bouk/httprouter"
	"github.com/influxdata/chronograf"
	"github.com/influxdata/chronograf/mocks"
)

func TestService_Queries(t *testing.T) {
	tests := []struct {
		name         string
		SourcesStore chronograf.SourcesStore
		ID           string
		w            *httptest.ResponseRecorder
		r            *http.Request
		want         string
	}{
		{
			name: "bad json",
			SourcesStore: &mocks.SourcesStore{
				GetF: func(ctx context.Context, ID int) (chronograf.Source, error) {
					return chronograf.Source{
						ID: ID,
					}, nil
				},
			},
			ID:   "1",
			w:    httptest.NewRecorder(),
			r:    httptest.NewRequest("POST", "/queries", bytes.NewReader([]byte(`howdy`))),
			want: `{"code":400,"message":"Unparsable JSON"}`,
		},
		{
			name: "bad id",
			ID:   "howdy",
			w:    httptest.NewRecorder(),
			r:    httptest.NewRequest("POST", "/queries", bytes.NewReader([]byte{})),
			want: `{"code":422,"message":"Error converting ID howdy"}`,
		},
		{
			name: "query with no template vars",
			SourcesStore: &mocks.SourcesStore{
				GetF: func(ctx context.Context, ID int) (chronograf.Source, error) {
					return chronograf.Source{
						ID: ID,
					}, nil
				},
			},
			ID: "1",
			w:  httptest.NewRecorder(),
			r: httptest.NewRequest("POST", "/queries", bytes.NewReader([]byte(`{
					"queries": [
					  {
						"query": "SELECT \"pingReq\" FROM db.\"monitor\".\"httpd\" WHERE time > now() - 1m",
						"id": "82b60d37-251e-4afe-ac93-ca20a3642b11"
					  }
					]}`))),
			want: `{"queries":[{"id":"82b60d37-251e-4afe-ac93-ca20a3642b11","query":"SELECT \"pingReq\" FROM db.\"monitor\".\"httpd\" WHERE time \u003e now() - 1m","queryConfig":{"id":"82b60d37-251e-4afe-ac93-ca20a3642b11","database":"db","measurement":"httpd","retentionPolicy":"monitor","fields":[{"value":"pingReq","type":"field","alias":""}],"tags":{},"groupBy":{"time":"","tags":[]},"areTagsAccepted":false,"rawText":null,"range":{"upper":"","lower":"now() - 1m"},"shifts":[]},"queryAST":{"condition":{"expr":"binary","op":"\u003e","lhs":{"expr":"reference","val":"time"},"rhs":{"expr":"binary","op":"-","lhs":{"expr":"call","name":"now"},"rhs":{"expr":"literal","val":"1m","type":"duration"}}},"fields":[{"column":{"expr":"reference","val":"pingReq"}}],"sources":[{"database":"db","retentionPolicy":"monitor","name":"httpd","type":"measurement"}]}}]}
`,
		},
		{
			name: "query with unparsable query",
			SourcesStore: &mocks.SourcesStore{
				GetF: func(ctx context.Context, ID int) (chronograf.Source, error) {
					return chronograf.Source{
						ID: ID,
					}, nil
				},
			},
			ID: "1",
			w:  httptest.NewRecorder(),
			r: httptest.NewRequest("POST", "/queries", bytes.NewReader([]byte(`{
					"queries": [
					  {
						"query": "SHOW DATABASES",
						"id": "82b60d37-251e-4afe-ac93-ca20a3642b11"
					  }
					]}`))),
			want: `{"queries":[{"id":"82b60d37-251e-4afe-ac93-ca20a3642b11","query":"SHOW DATABASES","queryConfig":{"id":"82b60d37-251e-4afe-ac93-ca20a3642b11","database":"","measurement":"","retentionPolicy":"","fields":[],"tags":{},"groupBy":{"time":"","tags":[]},"areTagsAccepted":false,"rawText":"SHOW DATABASES","range":null,"shifts":[]}}]}
`,
		},
		{
			name: "query with template vars",
			SourcesStore: &mocks.SourcesStore{
				GetF: func(ctx context.Context, ID int) (chronograf.Source, error) {
					return chronograf.Source{
						ID: ID,
					}, nil
				},
			},
			ID: "1",
			w:  httptest.NewRecorder(),
			r: httptest.NewRequest("POST", "/queries", bytes.NewReader([]byte(`{
					"queries": [
					  {
						"query": "SELECT \"pingReq\" FROM :dbs:.\"monitor\".\"httpd\" WHERE time > :dashboardTime: AND time < :upperDashboardTime: GROUP BY :interval:",
						"id": "82b60d37-251e-4afe-ac93-ca20a3642b11"
					  }
					],
					"tempVars": [
					  {
						"tempVar": ":dbs:",
						"values": [
						  {
							"value": "_internal",
							"type": "database",
							"selected": true
						  }
						],
						"id": "792eda0d-2bb2-4de6-a86f-1f652889b044",
						"type": "databases",
						"label": "",
						"query": {
						  "influxql": "SHOW DATABASES",
						  "measurement": "",
						  "tagKey": "",
						  "fieldKey": ""
						},
						"links": {
						  "self": "/chronograf/v1/dashboards/1/templates/792eda0d-2bb2-4de6-a86f-1f652889b044"
						}
					  },
					  {
						"id": "dashtime",
						"tempVar": ":dashboardTime:",
						"type": "constant",
						"values": [
						  {
							"value": "now() - 15m",
							"type": "constant",
							"selected": true
						  }
						]
					  },
					  {
						"id": "upperdashtime",
						"tempVar": ":upperDashboardTime:",
						"type": "constant",
						"values": [
						  {
							"value": "now()",
							"type": "constant",
							"selected": true
						  }
						]
					  },
					  {
						"id": "interval",
						"type": "constant",
						"tempVar": ":interval:",
						"values": [
							{
									"value": "1000",
									"type":  "resolution"
							},
							{
									"value": "3",
									"type":  "pointsPerPixel"
							}
					]
					  }
					]
				  }`))),
			want: `{"queries":[{"id":"82b60d37-251e-4afe-ac93-ca20a3642b11","query":"SELECT \"pingReq\" FROM :dbs:.\"monitor\".\"httpd\" WHERE time \u003e :dashboardTime: AND time \u003c :upperDashboardTime: GROUP BY :interval:","queryConfig":{"id":"82b60d37-251e-4afe-ac93-ca20a3642b11","database":"","measurement":"","retentionPolicy":"","fields":[],"tags":{},"groupBy":{"time":"","tags":[]},"areTagsAccepted":false,"rawText":"SELECT \"pingReq\" FROM :dbs:.\"monitor\".\"httpd\" WHERE time \u003e :dashboardTime: AND time \u003c :upperDashboardTime: GROUP BY :interval:","range":null,"shifts":[]},"queryTemplated":"SELECT \"pingReq\" FROM \"_internal\".\"monitor\".\"httpd\" WHERE time \u003e now() - 15m AND time \u003c now() GROUP BY time(2s)","tempVars":[{"tempVar":":upperDashboardTime:","values":[{"value":"now()","type":"constant","selected":true}]},{"tempVar":":dashboardTime:","values":[{"value":"now() - 15m","type":"constant","selected":true}]},{"tempVar":":dbs:","values":[{"value":"_internal","type":"database","selected":true}]},{"tempVar":":interval:","values":[{"value":"1000","type":"resolution","selected":false},{"value":"3","type":"pointsPerPixel","selected":false}]}]}]}
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			tt.r = tt.r.WithContext(httprouter.WithParams(
				context.Background(),
				httprouter.Params{
					{
						Key:   "id",
						Value: tt.ID,
					},
				}))
			s := &Service{
				SourcesStore: tt.SourcesStore,
				Logger:       &mocks.TestLogger{},
			}
			s.Queries(tt.w, tt.r)
			got := tt.w.Body.String()
			if got != tt.want {
				t.Errorf("got:\n%s\nwant:\n%s\n", got, tt.want)
			}
		})
	}
}
<commit_msg>Fix broken test due to stupid new line<commit_after>package server

import (
	"bytes"
	"context"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/bouk/httprouter"
	"github.com/influxdata/chronograf"
	"github.com/influxdata/chronograf/mocks"
)

func TestService_Queries(t *testing.T) {
	tests := []struct {
		name         string
		SourcesStore chronograf.SourcesStore
		ID           string
		w            *httptest.ResponseRecorder
		r            *http.Request
		want         string
	}{
		{
			name: "bad json",
			SourcesStore: &mocks.SourcesStore{
				GetF: func(ctx context.Context, ID int) (chronograf.Source, error) {
					return chronograf.Source{
						ID: ID,
					}, nil
				},
			},
			ID:   "1",
			w:    httptest.NewRecorder(),
			r:    httptest.NewRequest("POST", "/queries", bytes.NewReader([]byte(`howdy`))),
			want: `{"code":400,"message":"Unparsable JSON"}`,
		},
		{
			name: "bad id",
			ID:   "howdy",
			w:    httptest.NewRecorder(),
			r:    httptest.NewRequest("POST", "/queries", bytes.NewReader([]byte{})),
			want: `{"code":422,"message":"Error converting ID howdy"}`,
		},
		{
			name: "query with no template vars",
			SourcesStore: &mocks.SourcesStore{
				GetF: func(ctx context.Context, ID int) (chronograf.Source, error) {
					return chronograf.Source{
						ID: ID,
					}, nil
				},
			},
			ID: "1",
			w:  httptest.NewRecorder(),
			r: httptest.NewRequest("POST", "/queries", bytes.NewReader([]byte(`{
					"queries": [
					  {
						"query": "SELECT \"pingReq\" FROM db.\"monitor\".\"httpd\" WHERE time > now() - 1m",
						"id": "82b60d37-251e-4afe-ac93-ca20a3642b11"
					  }
					]}`))),
			want: `{"queries":[{"id":"82b60d37-251e-4afe-ac93-ca20a3642b11","query":"SELECT \"pingReq\" FROM db.\"monitor\".\"httpd\" WHERE time \u003e now() - 1m","queryConfig":{"id":"82b60d37-251e-4afe-ac93-ca20a3642b11","database":"db","measurement":"httpd","retentionPolicy":"monitor","fields":[{"value":"pingReq","type":"field","alias":""}],"tags":{},"groupBy":{"time":"","tags":[]},"areTagsAccepted":false,"rawText":null,"range":{"upper":"","lower":"now() - 1m"},"shifts":[]},"queryAST":{"condition":{"expr":"binary","op":"\u003e","lhs":{"expr":"reference","val":"time"},"rhs":{"expr":"binary","op":"-","lhs":{"expr":"call","name":"now"},"rhs":{"expr":"literal","val":"1m","type":"duration"}}},"fields":[{"column":{"expr":"reference","val":"pingReq"}}],"sources":[{"database":"db","retentionPolicy":"monitor","name":"httpd","type":"measurement"}]}}]}
`,
		},
		{
			name: "query with unparsable query",
			SourcesStore: &mocks.SourcesStore{
				GetF: func(ctx context.Context, ID int) (chronograf.Source, error) {
					return chronograf.Source{
						ID: ID,
					}, nil
				},
			},
			ID: "1",
			w:  httptest.NewRecorder(),
			r: httptest.NewRequest("POST", "/queries", bytes.NewReader([]byte(`{
					"queries": [
					  {
						"query": "SHOW DATABASES",
						"id": "82b60d37-251e-4afe-ac93-ca20a3642b11"
					  }
					]}`))),
			want: `{"queries":[{"id":"82b60d37-251e-4afe-ac93-ca20a3642b11","query":"SHOW DATABASES","queryConfig":{"id":"82b60d37-251e-4afe-ac93-ca20a3642b11","database":"","measurement":"","retentionPolicy":"","fields":[],"tags":{},"groupBy":{"time":"","tags":[]},"areTagsAccepted":false,"rawText":"SHOW DATABASES","range":null,"shifts":[]}}]}
`,
		},
		{
			name: "query with template vars",
			SourcesStore: &mocks.SourcesStore{
				GetF: func(ctx context.Context, ID int) (chronograf.Source, error) {
					return chronograf.Source{
						ID: ID,
					}, nil
				},
			},
			ID: "1",
			w:  httptest.NewRecorder(),
			r: httptest.NewRequest("POST", "/queries", bytes.NewReader([]byte(`{
					"queries": [
					  {
						"query": "SELECT \"pingReq\" FROM :dbs:.\"monitor\".\"httpd\" WHERE time > :dashboardTime: AND time < :upperDashboardTime: GROUP BY :interval:",
						"id": "82b60d37-251e-4afe-ac93-ca20a3642b11"
					  }
					],
					"tempVars": [
					  {
						"tempVar": ":dbs:",
						"values": [
						  {
							"value": "_internal",
							"type": "database",
							"selected": true
						  }
						],
						"id": "792eda0d-2bb2-4de6-a86f-1f652889b044",
						"type": "databases",
						"label": "",
						"query": {
						  "influxql": "SHOW DATABASES",
						  "measurement": "",
						  "tagKey": "",
						  "fieldKey": ""
						},
						"links": {
						  "self": "/chronograf/v1/dashboards/1/templates/792eda0d-2bb2-4de6-a86f-1f652889b044"
						}
					  },
					  {
						"id": "dashtime",
						"tempVar": ":dashboardTime:",
						"type": "constant",
						"values": [
						  {
							"value": "now() - 15m",
							"type": "constant",
							"selected": true
						  }
						]
					  },
					  {
						"id": "upperdashtime",
						"tempVar": ":upperDashboardTime:",
						"type": "constant",
						"values": [
						  {
							"value": "now()",
							"type": "constant",
							"selected": true
						  }
						]
					  },
					  {
						"id": "interval",
						"type": "constant",
						"tempVar": ":interval:",
						"values": [
							{
									"value": "1000",
									"type":  "resolution"
							},
							{
									"value": "3",
									"type":  "pointsPerPixel"
							}
					]
					  }
					]
				  }`))),
			want: `{"queries":[{"id":"82b60d37-251e-4afe-ac93-ca20a3642b11","query":"SELECT \"pingReq\" FROM :dbs:.\"monitor\".\"httpd\" WHERE time \u003e :dashboardTime: AND time \u003c :upperDashboardTime: GROUP BY :interval:","queryConfig":{"id":"82b60d37-251e-4afe-ac93-ca20a3642b11","database":"","measurement":"","retentionPolicy":"","fields":[],"tags":{},"groupBy":{"time":"","tags":[]},"areTagsAccepted":false,"rawText":"SELECT \"pingReq\" FROM :dbs:.\"monitor\".\"httpd\" WHERE time \u003e :dashboardTime: AND time \u003c :upperDashboardTime: GROUP BY :interval:","range":null,"shifts":[]},"queryTemplated":"SELECT \"pingReq\" FROM \"_internal\".\"monitor\".\"httpd\" WHERE time \u003e now() - 15m AND time \u003c now() GROUP BY time(2s)","tempVars":[{"tempVar":":upperDashboardTime:","values":[{"value":"now()","type":"constant","selected":true}]},{"tempVar":":dashboardTime:","values":[{"value":"now() - 15m","type":"constant","selected":true}]},{"tempVar":":dbs:","values":[{"value":"_internal","type":"database","selected":true}]},{"tempVar":":interval:","values":[{"value":"1000","type":"resolution","selected":false},{"value":"3","type":"pointsPerPixel","selected":false}]}]}]}
`,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			tt.r = tt.r.WithContext(httprouter.WithParams(
				context.Background(),
				httprouter.Params{
					{
						Key:   "id",
						Value: tt.ID,
					},
				}))
			s := &Service{
				SourcesStore: tt.SourcesStore,
				Logger:       &mocks.TestLogger{},
			}
			s.Queries(tt.w, tt.r)
			got := tt.w.Body.String()
			if got != tt.want {
				t.Errorf("got:\n%s\nwant:\n%s\n", got, tt.want)
			}
		})
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Pulcy.
//
// 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 proxy

import (
	"io/ioutil"
	"os"
	"strings"

	"github.com/juju/errgo"

	"github.com/pulcy/gluon/service"
	"github.com/pulcy/gluon/util"
)

var (
	maskAny = errgo.MaskFunc(errgo.Any)
)

const (
	environment = "/etc/environment"
	dockerEnv   = "/etc/pulcy/docker.env"

	fileMode      = os.FileMode(0644)
	noProxyPrefix = "NO_PROXY="
)

func NewService() service.Service {
	return &proxyService{}
}

type proxyService struct{}

func (t *proxyService) Name() string {
	return "proxy"
}

func (t *proxyService) Setup(deps service.ServiceDependencies, flags *service.ServiceFlags) error {
	noProxy, err := createNoProxy(deps, flags)
	if err != nil {
		return maskAny(err)
	}
	if err := updateNoProxy(environment, noProxy, deps, flags); err != nil {
		return maskAny(err)
	}
	if err := updateNoProxy(dockerEnv, noProxy, deps, flags); err != nil {
		return maskAny(err)
	}

	return nil
}

// createNoProxy creates the value for the no_proxy environment variable.
func createNoProxy(deps service.ServiceDependencies, flags *service.ServiceFlags) (string, error) {
	members, err := flags.GetClusterMembers(deps.Logger)
	if err != nil {
		return "", maskAny(err)
	}
	list := []string{".private"}
	for _, cm := range members {
		list = append(list, cm.ClusterIP)
		if cm.ClusterIP != cm.PrivateHostIP {
			list = append(list, cm.PrivateHostIP)
		}
	}
	return strings.Join(list, ","), nil
}

func updateNoProxy(path, noProxy string, deps service.ServiceDependencies, flags *service.ServiceFlags) error {
	deps.Logger.Info("updating %s", path)
	if _, err := os.Stat(path); os.IsNotExist(err) {
		return nil
	}

	origContent, err := ioutil.ReadFile(path)
	if err != nil {
		return maskAny(err)
	}
	lines := strings.Split(string(origContent), "\n")
	updatedLines := []string{}
	for _, line := range lines {
		line = strings.TrimSpace(line)
		if !strings.HasPrefix(strings.ToUpper(line), noProxyPrefix) && line != "" {
			updatedLines = append(updatedLines, line)
		}
	}
	updatedLines = append(updatedLines, noProxyPrefix+noProxy)

	newContent := strings.Join(updatedLines, "\n")
	if _, err := util.UpdateFile(path, []byte(newContent), fileMode); err != nil {
		return maskAny(err)
	}
	return nil
}
<commit_msg>Added .local to NO_PROXY list<commit_after>// Copyright (c) 2016 Pulcy.
//
// 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 proxy

import (
	"io/ioutil"
	"os"
	"strings"

	"github.com/juju/errgo"

	"github.com/pulcy/gluon/service"
	"github.com/pulcy/gluon/util"
)

var (
	maskAny = errgo.MaskFunc(errgo.Any)
)

const (
	environment = "/etc/environment"
	dockerEnv   = "/etc/pulcy/docker.env"

	fileMode      = os.FileMode(0644)
	noProxyPrefix = "NO_PROXY="
)

func NewService() service.Service {
	return &proxyService{}
}

type proxyService struct{}

func (t *proxyService) Name() string {
	return "proxy"
}

func (t *proxyService) Setup(deps service.ServiceDependencies, flags *service.ServiceFlags) error {
	noProxy, err := createNoProxy(deps, flags)
	if err != nil {
		return maskAny(err)
	}
	if err := updateNoProxy(environment, noProxy, deps, flags); err != nil {
		return maskAny(err)
	}
	if err := updateNoProxy(dockerEnv, noProxy, deps, flags); err != nil {
		return maskAny(err)
	}

	return nil
}

// createNoProxy creates the value for the no_proxy environment variable.
func createNoProxy(deps service.ServiceDependencies, flags *service.ServiceFlags) (string, error) {
	members, err := flags.GetClusterMembers(deps.Logger)
	if err != nil {
		return "", maskAny(err)
	}
	list := []string{".local", ".private"}
	for _, cm := range members {
		list = append(list, cm.ClusterIP)
		if cm.ClusterIP != cm.PrivateHostIP {
			list = append(list, cm.PrivateHostIP)
		}
	}
	return strings.Join(list, ","), nil
}

func updateNoProxy(path, noProxy string, deps service.ServiceDependencies, flags *service.ServiceFlags) error {
	deps.Logger.Info("updating %s", path)
	if _, err := os.Stat(path); os.IsNotExist(err) {
		return nil
	}

	origContent, err := ioutil.ReadFile(path)
	if err != nil {
		return maskAny(err)
	}
	lines := strings.Split(string(origContent), "\n")
	updatedLines := []string{}
	for _, line := range lines {
		line = strings.TrimSpace(line)
		if !strings.HasPrefix(strings.ToUpper(line), noProxyPrefix) && line != "" {
			updatedLines = append(updatedLines, line)
		}
	}
	updatedLines = append(updatedLines, noProxyPrefix+noProxy)

	newContent := strings.Join(updatedLines, "\n")
	if _, err := util.UpdateFile(path, []byte(newContent), fileMode); err != nil {
		return maskAny(err)
	}
	return nil
}
<|endoftext|>


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

package metrics

import (
	"strings"
	"testing"

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

func TestSimilarPercentage(t *testing.T) {
	assert := require.New(t)

	sentence := "this is some words about nothing, Hugo!"
	words := strings.Fields(sentence)
	for i, j := 0, len(words)-1; i < j; i, j = i+1, j-1 {
		words[i], words[j] = words[j], words[i]
	}
	sentenceReversed := strings.Join(words, " ")

	assert.Equal(100, howSimilar("Hugo Rules", "Hugo Rules"))
	assert.Equal(50, howSimilar("Hugo Rules", "Hugo Rocks"))
	assert.Equal(66, howSimilar("The Hugo Rules", "The Hugo Rocks"))
	assert.Equal(66, howSimilar("The Hugo Rules", "The Hugo"))
	assert.Equal(66, howSimilar("The Hugo", "The Hugo Rules"))
	assert.Equal(0, howSimilar("Totally different", "Not Same"))
	assert.Equal(14, howSimilar(sentence, sentenceReversed))

}

func BenchmarkHowSimilar(b *testing.B) {
	s1 := "Hugo is cool and " + strings.Repeat("fun ", 10) + "!"
	s2 := "Hugo is cool and " + strings.Repeat("cool ", 10) + "!"

	for i := 0; i < b.N; i++ {
		howSimilar(s1, s2)
	}
}
<commit_msg>metrics: Reset benchmark timer<commit_after>// Copyright 2017 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package metrics

import (
	"strings"
	"testing"

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

func TestSimilarPercentage(t *testing.T) {
	assert := require.New(t)

	sentence := "this is some words about nothing, Hugo!"
	words := strings.Fields(sentence)
	for i, j := 0, len(words)-1; i < j; i, j = i+1, j-1 {
		words[i], words[j] = words[j], words[i]
	}
	sentenceReversed := strings.Join(words, " ")

	assert.Equal(100, howSimilar("Hugo Rules", "Hugo Rules"))
	assert.Equal(50, howSimilar("Hugo Rules", "Hugo Rocks"))
	assert.Equal(66, howSimilar("The Hugo Rules", "The Hugo Rocks"))
	assert.Equal(66, howSimilar("The Hugo Rules", "The Hugo"))
	assert.Equal(66, howSimilar("The Hugo", "The Hugo Rules"))
	assert.Equal(0, howSimilar("Totally different", "Not Same"))
	assert.Equal(14, howSimilar(sentence, sentenceReversed))

}

func BenchmarkHowSimilar(b *testing.B) {
	s1 := "Hugo is cool and " + strings.Repeat("fun ", 10) + "!"
	s2 := "Hugo is cool and " + strings.Repeat("cool ", 10) + "!"

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		howSimilar(s1, s2)
	}
}
<|endoftext|>


<commit_before>package server

import (
	"fmt"
	"io"
	"io/ioutil"

	"github.com/containers/storage/pkg/pools"
	"github.com/cri-o/cri-o/internal/log"
	"github.com/cri-o/cri-o/internal/oci"
	"github.com/pkg/errors"
	"golang.org/x/net/context"
	pb "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
)

// PortForward prepares a streaming endpoint to forward ports from a PodSandbox.
func (s *Server) PortForward(ctx context.Context, req *pb.PortForwardRequest) (*pb.PortForwardResponse, error) {
	resp, err := s.getPortForward(req)
	if err != nil {
		return nil, fmt.Errorf("unable to prepare portforward endpoint")
	}

	return resp, nil
}

func (s StreamService) PortForward(podSandboxID string, port int32, stream io.ReadWriteCloser) error {
	ctx := log.AddRequestNameAndID(context.Background(), "PortForward")

	// if we error in this function before Copying all of the content out of the stream,
	// this stream will eventually get full, which causes leakages and can eventually brick CRI-O
	// ref https://bugzilla.redhat.com/show_bug.cgi?id=1798193
	emptyStreamOnError := true
	defer func() {
		if emptyStreamOnError && stream != nil {
			go func() {
				_, copyError := pools.Copy(ioutil.Discard, stream)
				log.Errorf(ctx, "error closing port forward stream after other error: %v", copyError)
			}()
		}
	}()

	sandboxID, err := s.runtimeServer.PodIDIndex().Get(podSandboxID)
	if err != nil {
		return fmt.Errorf("PodSandbox with ID starting with %s not found: %v", podSandboxID, err)
	}

	sb := s.runtimeServer.GetSandbox(sandboxID)
	if sb == nil {
		return fmt.Errorf("could not find sandbox %s", podSandboxID)
	}

	c := sb.InfraContainer()
	if err := s.runtimeServer.Runtime().UpdateContainerStatus(c); err != nil {
		return err
	}

	cState := c.State()
	if !(cState.Status == oci.ContainerStateRunning || cState.Status == oci.ContainerStateCreated) {
		return fmt.Errorf("container is not created or running")
	}

	emptyStreamOnError = false

	if sb.NetNsPath() == "" {
		return errors.Errorf(
			"network namespace path of sandbox %s is empty", sb.ID(),
		)
	}

	return s.runtimeServer.Runtime().PortForwardContainer(ctx, c, sb.NetNsPath(), port, stream)
}
<commit_msg>portforward: rework to not need infra container<commit_after>package server

import (
	"fmt"
	"io"
	"io/ioutil"

	"github.com/containers/storage/pkg/pools"
	"github.com/cri-o/cri-o/internal/log"
	"github.com/pkg/errors"
	"golang.org/x/net/context"
	pb "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
)

// PortForward prepares a streaming endpoint to forward ports from a PodSandbox.
func (s *Server) PortForward(ctx context.Context, req *pb.PortForwardRequest) (*pb.PortForwardResponse, error) {
	resp, err := s.getPortForward(req)
	if err != nil {
		return nil, fmt.Errorf("unable to prepare portforward endpoint")
	}

	return resp, nil
}

func (s StreamService) PortForward(podSandboxID string, port int32, stream io.ReadWriteCloser) error {
	ctx := log.AddRequestNameAndID(context.Background(), "PortForward")

	// if we error in this function before Copying all of the content out of the stream,
	// this stream will eventually get full, which causes leakages and can eventually brick CRI-O
	// ref https://bugzilla.redhat.com/show_bug.cgi?id=1798193
	emptyStreamOnError := true
	defer func() {
		if emptyStreamOnError && stream != nil {
			go func() {
				_, copyError := pools.Copy(ioutil.Discard, stream)
				log.Errorf(ctx, "error closing port forward stream after other error: %v", copyError)
			}()
		}
	}()

	sandboxID, err := s.runtimeServer.PodIDIndex().Get(podSandboxID)
	if err != nil {
		return fmt.Errorf("PodSandbox with ID starting with %s not found: %v", podSandboxID, err)
	}

	sb := s.runtimeServer.GetSandbox(sandboxID)
	if sb == nil {
		return fmt.Errorf("could not find sandbox %s", podSandboxID)
	}

	if !sb.Ready(true) {
		return fmt.Errorf("sandbox %s is not running", podSandboxID)
	}

	netNsPath := sb.NetNsPath()
	if netNsPath == "" {
		return errors.Errorf(
			"network namespace path of sandbox %s is empty", sb.ID(),
		)
	}

	// defer responsibility of emptying stream to PortForwardContainer
	emptyStreamOnError = false

	return s.runtimeServer.Runtime().PortForwardContainer(ctx, sb.InfraContainer(), netNsPath, port, stream)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"net"

	_ "golang.org/x/net/context"
	"google.golang.org/grpc"

	"errors"
	"github.com/afg984/thegame/server/go/src/thegame/pb"
)

var listen string

func init() {
	flag.StringVar(&listen, "listen", ":50051", "[host]:port to listen to")
}

type server struct {
	arena *Arena
	token string // XXX currently it is empty
}

func NewServer() *server {
	return &server{
		arena: NewArena(),
	}
}

func (s *server) Game(stream pb.TheGame_GameServer) error {
	log.Println("New client connected")
	join, err := stream.Recv()
	if err != nil {
		log.Println(err)
		return err
	}
	element := s.arena.Join(join.Name)
	hero := element.Value.(*Hero)
	go func() {
		updates := hero.UpdateChan
		for gameState := range updates {
			err := stream.Send(gameState)
			if err != nil {
				log.Println(err)
			}
		}
	}()
	defer s.arena.Quit(element)
	for {
		controls, err := stream.Recv()
		if err != nil {
			log.Println(err)
			return err
		}
		s.arena.controlChan <- HeroControls{
			Hero:     hero,
			Controls: controls,
		}
	}
}

func (s *server) View(view *pb.ViewRequest, stream pb.TheGame_ViewServer) error {
	if s.token != view.Token {
		return errors.New("Invalid token")
	}
	ch := make(chan *pb.GameState, 16)
	s.arena.viewChan <- ch
	for gs := range ch {
		err := stream.Send(gs)
		if err != nil {
			log.Println(err)
			return err
		}
	}
	return nil
}

func main() {
	flag.Parse()
	lis, err := net.Listen("tcp", listen)
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}
	s := grpc.NewServer()
	gs := NewServer()
	pb.RegisterTheGameServer(s, gs)
	log.Println("listening on", listen)
	go func() {
		for {
			var line string
			fmt.Scanln(&line)
			switch line {
			case "p":
				gs.arena.commandChan <- Pause
			case "r":
				gs.arena.commandChan <- Resume
			default:
				fmt.Printf("Unknown command: %q\n", line)
			}
		}
	}()
	if err := s.Serve(lis); err != nil {
		log.Fatalf("failed to serve: %v", err)
	}
}
<commit_msg>server/go: show better grpc error messages<commit_after>package main

import (
	"errors"
	"flag"
	"fmt"
	"log"
	"net"

	_ "golang.org/x/net/context"
	"google.golang.org/grpc"

	"github.com/afg984/thegame/server/go/src/thegame/pb"
)

var listen string

func init() {
	flag.StringVar(&listen, "listen", ":50051", "[host]:port to listen to")
}

type server struct {
	arena *Arena
	token string // XXX currently it is empty
}

func NewServer() *server {
	return &server{
		arena: NewArena(),
	}
}

func (s *server) Game(stream pb.TheGame_GameServer) error {
	log.Println("New client connected")
	join, err := stream.Recv()
	if err != nil {
		log.Printf("join initialization failed: %v", err)
		return err
	}
	element := s.arena.Join(join.Name)
	hero := element.Value.(*Hero)
	go func() {
		updates := hero.UpdateChan
		for gameState := range updates {
			err := stream.Send(gameState)
			if err != nil {
				log.Printf("cannot send gameState to %v: %v", hero, err)
			}
		}
	}()
	defer s.arena.Quit(element)
	for {
		controls, err := stream.Recv()
		if err != nil {
			log.Printf("cannot receive controls from %v: %v", hero, err)
			return err
		}
		s.arena.controlChan <- HeroControls{
			Hero:     hero,
			Controls: controls,
		}
	}
}

func (s *server) View(view *pb.ViewRequest, stream pb.TheGame_ViewServer) error {
	if s.token != view.Token {
		return errors.New("Invalid token")
	}
	ch := make(chan *pb.GameState, 16)
	s.arena.viewChan <- ch
	for gs := range ch {
		err := stream.Send(gs)
		if err != nil {
			log.Printf("cannot send gameState to audience: %v", err)
			return err
		}
	}
	return nil
}

func main() {
	flag.Parse()
	lis, err := net.Listen("tcp", listen)
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}
	s := grpc.NewServer()
	gs := NewServer()
	pb.RegisterTheGameServer(s, gs)
	log.Println("listening on", listen)
	go func() {
		for {
			var line string
			fmt.Scanln(&line)
			switch line {
			case "p":
				gs.arena.commandChan <- Pause
			case "r":
				gs.arena.commandChan <- Resume
			default:
				fmt.Printf("Unknown command: %q\n", line)
			}
		}
	}()
	if err := s.Serve(lis); err != nil {
		log.Fatalf("failed to serve: %v", err)
	}
}
<|endoftext|>


<commit_before>package response

import (
	"warcluster/entities"
)

type StateChange struct {
	baseResponse
	Missions map[string]entities.Entity `json:",omitempty"`
	Planets  map[string]entities.Entity `json:",omitempty"`
	Suns     map[string]entities.Entity `json:",omitempty"`
	Entities map[string]entities.Entity `json:",omitempty"`
}

func NewStateChange() *StateChange {
	r := new(StateChange)
	r.Command = "state_change"
	return r
}
<commit_msg>Remove StateChange.Entities<commit_after>package response

import (
	"warcluster/entities"
)

type StateChange struct {
	baseResponse
	Missions map[string]entities.Entity `json:",omitempty"`
	Planets  map[string]entities.Entity `json:",omitempty"`
	Suns     map[string]entities.Entity `json:",omitempty"`
}

func NewStateChange() *StateChange {
	r := new(StateChange)
	r.Command = "state_change"
	return r
}
<|endoftext|>


<commit_before>/*
    Ataxia Mud Engine

    Copyright © 2009-2010 Xenith Studios
*/
package main

import (
	"fmt"
	"flag"
	"os"
	"os/signal"
	"syscall"
	"log"
	"ataxia/lua"
	"ataxia/settings"
)

// Variables for the command-line flags
var (
	portFlag int
	configFlag string
	hotbootFlag bool
	descriptorFlag int
)

var shutdown chan bool

// Do all our basic initialization within the main package's init function.
func init() {
	fmt.Printf(`Ataxia Engine %s © 2009-2011, Xenith Studios (see AUTHORS)
Compiled on %s
Ataxia Engine comes with ABSOLUTELY NO WARRANTY; see COPYING for details.
This is free software, and you are welcome to redistribute it
under certain conditions; for details, see the file COPYING.

`, ATAXIA_VERSION, ATAXIA_COMPILED);

	shutdown = make(chan bool)
	// Setup the command-line flags
	flag.IntVar(&portFlag, "port", 0, "Main port")
	flag.StringVar(&configFlag, "config", "etc/config.lua", "Config file")
	flag.BoolVar(&hotbootFlag, "hotboot", false, "Recover from hotboot")
	flag.IntVar(&descriptorFlag, "descriptor", 0, "Hotboot descriptor")

	// Parse the command line
	flag.Parse()

	// Initialize Lua
	lua.Initialize()

	// Read configuration file
	ok := settings.LoadConfigFile(configFlag, portFlag)
	if !ok {
		log.Fatal("Error reading config file.")
	}

	// Initializations
		// Environment
		// Logging
		// Queues
		// Database

	if !hotbootFlag {
		// If previous shutdown was not clean and we are not recovering from a hotboot, clean up state and environment
	}
}

// When hotboot is called, this function will save game and world state, save each player state, and save the player list.
// Then it will do some cleanup (including closing the database) and call Exec to reload the running program.
func hotboot() {
	// Save game state
	// Save socket and player list
	// Disconnect from database
	arglist := append(os.Args, "-hotboot", "-descriptor=", fmt.Sprint(1234))
	os.Exec(os.Args[0], arglist, os.Environ())

	// If we get to this point, something went wrong. Die.
	log.Fatal("Failed to exec during hotboot.")
}

// When recovering from a hotboot, recover will restore the game and world state, restore the player list, and restore each player state.
// Once that is done, it will then reconnect each active descriptor to the associated player.
func recover() {
	log.Println("Recovering from hotboot.")
}

//
func main() {
	// At this point, basic initialization has completed

	// Spin up a goroutine to handle signals
	go func() {
		for sig := range signal.Incoming {
			if usig,ok := sig.(signal.UnixSignal); ok {
				switch usig {
					case syscall.SIGQUIT: fallthrough
					case syscall.SIGTERM: fallthrough
					case syscall.SIGINT:
						// Catch the three interrupt signals and signal the game to shutdown.
						shutdown <- true
					case syscall.SIGHUP:
						// TODO: Reload settings and game state
					case syscall.SIGTSTP:
						// Pass on the SIGSTP signal through the syscall mechanism. This actually works.
						syscall.Kill(syscall.Getpid(), syscall.SIGSTOP)
				}
			}
		}
	}()

	// If configured, chroot into the designated directory
	if settings.Chroot != "" {
		err := syscall.Chroot(settings.Chroot)
		if err != 0 {
			log.Fatalln("Failed to chroot:", os.Errno(err))
		}
		error := os.Chdir("/")
		if error != nil {
			log.Fatalln("Failed to chdir:", error)
		}
		log.Println("Chrooted to", settings.Chroot)
	}

	// Drop priviledges if configured

	// Daemonize if configured
	if settings.Daemonize {
		log.Println("Daemonizing")
		// Daemonize here
		// TODO: This probably won't be doable until Go supports forking into the background.
	}

	// Write out pid file
	pid := fmt.Sprint(os.Getpid())
	pidfile, err := os.Open(settings.Pidfile, os.O_RDWR|os.O_CREAT, 0666)
	if pidfile == nil {
		log.Fatalln("Error writing pid to file:", err)
	}
	pidfile.Write([]byte(pid))
	log.Println("Wrote PID to", settings.Pidfile)
	pidfile.Close()
	defer os.Remove(settings.Pidfile)

	// Initialize the network
	log.Println("Initializing network")
	server := NewServer(settings.MainPort, shutdown)

	// Initialize game state
		// Load database
		// Load commands
		// Load scripts
		// Load world
		// Load entities

	// Are we recovering from a hotboot?
	if hotbootFlag {
		recover()
	}

	// Initialization and setup is complete. Spin up a goroutine to handle incoming connections
	go server.Listen()

	// Run the game loop in its own goroutine
	go server.Run()

	// Wait for the shutdown signal
	<-shutdown

	// Cleanup
	log.Println("Cleaning up....")
	lua.Shutdown()
	server.Shutdown()
}
<commit_msg>Bump the year in the copyright. Fixup for current version of Go.<commit_after>/*
    Ataxia Mud Engine

    Copyright © 2009-2011 Xenith Studios
*/
package main

import (
	"fmt"
	"flag"
	"os"
	"os/signal"
	"syscall"
	"log"
	"ataxia/lua"
	"ataxia/settings"
)

// Variables for the command-line flags
var (
	portFlag int
	configFlag string
	hotbootFlag bool
	descriptorFlag int
)

var shutdown chan bool

// Do all our basic initialization within the main package's init function.
func init() {
	fmt.Printf(`Ataxia Engine %s © 2009-2011, Xenith Studios (see AUTHORS)
Compiled on %s
Ataxia Engine comes with ABSOLUTELY NO WARRANTY; see COPYING for details.
This is free software, and you are welcome to redistribute it
under certain conditions; for details, see the file COPYING.

`, ATAXIA_VERSION, ATAXIA_COMPILED)

	shutdown = make(chan bool)
	// Setup the command-line flags
	flag.IntVar(&portFlag, "port", 0, "Main port")
	flag.StringVar(&configFlag, "config", "etc/config.lua", "Config file")
	flag.BoolVar(&hotbootFlag, "hotboot", false, "Recover from hotboot")
	flag.IntVar(&descriptorFlag, "descriptor", 0, "Hotboot descriptor")

	// Parse the command line
	flag.Parse()

	// Initialize Lua
	lua.Initialize()

	// Read configuration file
	ok := settings.LoadConfigFile(configFlag, portFlag)
	if !ok {
		log.Fatal("Error reading config file.")
	}

	// Initializations
		// Environment
		// Logging
		// Queues
		// Database

	if !hotbootFlag {
		// If previous shutdown was not clean and we are not recovering from a hotboot, clean up state and environment
	}
}

// When hotboot is called, this function will save game and world state, save each player state, and save the player list.
// Then it will do some cleanup (including closing the database) and call Exec to reload the running program.
func hotboot() {
	// Save game state
	// Save socket and player list
	// Disconnect from database
	arglist := append(os.Args, "-hotboot", "-descriptor=", fmt.Sprint(1234))
	os.Exec(os.Args[0], arglist, os.Environ())

	// If we get to this point, something went wrong. Die.
	log.Fatal("Failed to exec during hotboot.")
}

// When recovering from a hotboot, recover will restore the game and world state, restore the player list, and restore each player state.
// Once that is done, it will then reconnect each active descriptor to the associated player.
func recover() {
	log.Println("Recovering from hotboot.")
}

//
func main() {
	// At this point, basic initialization has completed

	// Spin up a goroutine to handle signals
	go func() {
		for sig := range signal.Incoming {
			if usig,ok := sig.(signal.UnixSignal); ok {
				switch usig {
					case syscall.SIGQUIT: fallthrough
					case syscall.SIGTERM: fallthrough
					case syscall.SIGINT:
						// Catch the three interrupt signals and signal the game to shutdown.
						shutdown <- true
					case syscall.SIGHUP:
						// TODO: Reload settings and game state
					case syscall.SIGTSTP:
						// Pass on the SIGSTP signal through the syscall mechanism. This actually works.
						syscall.Kill(syscall.Getpid(), syscall.SIGSTOP)
				}
			}
		}
	}()

	// If configured, chroot into the designated directory
	if settings.Chroot != "" {
		err := syscall.Chroot(settings.Chroot)
		if err != 0 {
			log.Fatalln("Failed to chroot:", os.Errno(err))
		}
		error := os.Chdir("/")
		if error != nil {
			log.Fatalln("Failed to chdir:", error)
		}
		log.Println("Chrooted to", settings.Chroot)
	}

	// Drop priviledges if configured

	// Daemonize if configured
	if settings.Daemonize {
		log.Println("Daemonizing")
		// Daemonize here
		// TODO: This probably won't be doable until Go supports forking into the background.
	}

	// Write out pid file
	pid := fmt.Sprint(os.Getpid())
	pidfile, err := os.Create(settings.Pidfile)
	if pidfile == nil {
		log.Fatalln("Error writing pid to file:", err)
	}
	pidfile.Write([]byte(pid))
	log.Println("Wrote PID to", settings.Pidfile)
	pidfile.Close()
	defer os.Remove(settings.Pidfile)

	// Initialize the network
	log.Println("Initializing network")
	server := NewServer(settings.MainPort, shutdown)

	// Initialize game state
		// Load database
		// Load commands
		// Load scripts
		// Load world
		// Load entities

	// Are we recovering from a hotboot?
	if hotbootFlag {
		recover()
	}

	// Initialization and setup is complete. Spin up a goroutine to handle incoming connections
	go server.Listen()

	// Run the game loop in its own goroutine
	go server.Run()

	// Wait for the shutdown signal
	<-shutdown

	// Cleanup
	log.Println("Cleaning up....")
	lua.Shutdown()
	server.Shutdown()
}
<|endoftext|>


<commit_before>package block

import (
	"github.com/jung-kurt/gofpdf"
	"net/http"
)

type Image struct {
	Url string  `mapstructure:"url"`
	X   float64 `mapstructure:"x"`
	Y   float64 `mapstructure:"y"`
	W   float64 `mapstructure:"w"`
	H   float64 `mapstructure:"h"`
}

func (i *Image) Parse(pdf *gofpdf.Fpdf, input map[string]interface{}) {
	i.Url = i.urlFromInput(input)

	registerRemoteImage(pdf, i.Url)
	pdf.Image(i.Url, i.X, i.Y, i.W, i.H, false, "", 0, "")
}

func (i *Image) Load(data interface{}) {
}

func (i *Image) urlFromInput(input map[string]interface{}) string {
	return input["url"].(string)
}

func registerRemoteImage(pdf *gofpdf.Fpdf, urlStr string) {
	resp, err := http.Get(urlStr)

	if err != nil {
		pdf.SetError(err)
		return
	}

	defer resp.Body.Close()

	tp := pdf.ImageTypeFromMime(resp.Header["Content-Type"][0])

	pdf.RegisterImageReader(urlStr, tp, resp.Body)
}
<commit_msg>Image: use gofpdf httpimg package.<commit_after>package block

import (
	"github.com/jung-kurt/gofpdf"
	"github.com/jung-kurt/gofpdf/contrib/httpimg"
)

type Image struct {
	Url string  `mapstructure:"url"`
	X   float64 `mapstructure:"x"`
	Y   float64 `mapstructure:"y"`
	W   float64 `mapstructure:"w"`
	H   float64 `mapstructure:"h"`
}

func (i *Image) Parse(pdf *gofpdf.Fpdf, input map[string]interface{}) {
	i.Url = i.urlFromInput(input)

	httpimg.Register(pdf, i.Url, "")
	pdf.Image(i.Url, i.X, i.Y, i.W, i.H, false, "", 0, "")
}

func (i *Image) Load(data interface{}) {
}

func (i *Image) urlFromInput(input map[string]interface{}) string {
	return input["url"].(string)
}
<|endoftext|>


<commit_before>package gollection_test

import (
	"testing"
	"time"

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

func TestSkip(t *testing.T) {
	assert := assert.New(t)
	arr := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
	expect := []int{4, 5, 6, 7, 8, 9, 10}

	res, err := gollection.New(arr).Skip(3).Result()
	assert.NoError(err)
	assert.Equal(expect, res)

	expect = []int{}
	res, err = gollection.New(arr).Skip(30).Result()
	assert.NoError(err)
	assert.Equal(expect, res)
}

func TestSkip_NotSlice(t *testing.T) {
	assert := assert.New(t)
	_, err := gollection.New("not slice value").Skip(0).Result()
	assert.Error(err)
}

func TestSkip_HavingError(t *testing.T) {
	assert := assert.New(t)
	_, err := gollection.New("not slice value").Skip(0).Skip(0).Result()
	assert.Error(err)
}

func TestSkip_Stream(t *testing.T) {
	assert := assert.New(t)
	arr := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
	expect := []int{4, 5, 6, 7, 8, 9, 10}

	res, err := gollection.NewStream(arr).Skip(3).Result()
	assert.NoError(err)
	assert.Equal(expect, res)

	expect = []int{}
	res, err = gollection.NewStream(arr).Skip(30).Result()
	assert.NoError(err)
	assert.Equal(expect, res)

	gollection.NewStream(arr).Filter(func(v int) bool {
		time.Sleep(1)
		return true
	}).Skip(100)
}

func TestSkip_Stream_NotSlice(t *testing.T) {
	assert := assert.New(t)
	_, err := gollection.NewStream("not slice value").Skip(0).Result()
	assert.Error(err)
}

func TestSkip_Stream_HavingError(t *testing.T) {
	assert := assert.New(t)
	_, err := gollection.NewStream("not slice value").Skip(0).Skip(0).Result()
	assert.Error(err)
}
<commit_msg>add skip test<commit_after>package gollection_test

import (
	"testing"
	"time"

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

func TestSkip(t *testing.T) {
	assert := assert.New(t)
	arr := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
	expect := []int{4, 5, 6, 7, 8, 9, 10}

	res, err := gollection.New(arr).Skip(3).Result()
	assert.NoError(err)
	assert.Equal(expect, res)

	expect = []int{}
	res, err = gollection.New(arr).Skip(30).Result()
	assert.NoError(err)
	assert.Equal(expect, res)
}

func TestSkip_NotSlice(t *testing.T) {
	assert := assert.New(t)
	_, err := gollection.New("not slice value").Skip(0).Result()
	assert.Error(err)
}

func TestSkip_InvalidArgument(t *testing.T) {
	assert := assert.New(t)
	_, err := gollection.New([]int{1, 2, 3}).Skip(-1).Result()
	assert.Error(err)
}

func TestSkip_HavingError(t *testing.T) {
	assert := assert.New(t)
	_, err := gollection.New("not slice value").Skip(0).Skip(0).Result()
	assert.Error(err)
}

func TestSkip_Stream(t *testing.T) {
	assert := assert.New(t)
	arr := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
	expect := []int{4, 5, 6, 7, 8, 9, 10}

	res, err := gollection.NewStream(arr).Skip(3).Result()
	assert.NoError(err)
	assert.Equal(expect, res)

	expect = []int{}
	res, err = gollection.NewStream(arr).Skip(30).Result()
	assert.NoError(err)
	assert.Equal(expect, res)

	gollection.NewStream(arr).Filter(func(v int) bool {
		time.Sleep(1)
		return true
	}).Skip(100)
}

func TestSkip_Stream_NotSlice(t *testing.T) {
	assert := assert.New(t)
	_, err := gollection.NewStream("not slice value").Skip(0).Result()
	assert.Error(err)
}

func TestSkip_Stream_HavingError(t *testing.T) {
	assert := assert.New(t)
	_, err := gollection.NewStream("not slice value").Skip(0).Skip(0).Result()
	assert.Error(err)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
)

type Response struct {
	Text        string        `json:"text"`
	Attachments []Attachments `json:"attachments"`
}

type Attachments struct {
	Title      string `json:"title"`
	Title_link string `json:"title_link"`
	Thumb_url  string `json:"thumb_url"`
}

type jsonData struct {
	Status  int64
	Message string
	Data    []Data
}

type Data struct {
	Id      string
	Caption string
	Images  struct {
		Small  string
		Cover  string
		Normal string
		Large  string
	}
	Media interface{}
	Link  string
	Votes struct {
		Count int64
	}
	Comments struct {
		Count int64
	}
}

func main() {
	http.HandleFunc("/", handler)
	fmt.Println("listening...")
	err := http.ListenAndServe(":"+os.Getenv("PORT"), nil)
	if err != nil {
		panic(err)
	}
}

func handler(w http.ResponseWriter, r *http.Request) {
	// Read the Request Parameter "command"
	command := r.FormValue("command")

	if command == "/9gag" {
		text := r.FormValue("text")
		fmt.Println(text)
		r, err := http.Get("http://infinigag.k3min.eu")
		if err != nil {
			fmt.Println("Error requesting data")
			return
		}
		body, err := ioutil.ReadAll(r.Body)
		if err != nil {
			fmt.Println("Error while opening file", err)
			return
		}
		x := new(jsonData)
		err = json.Unmarshal(body, &x)
		if err != nil {
			fmt.Println("Error while parsing file", err)
			return
		}
		jsonResp(w, x)
	} else {
		fmt.Fprint(w, "I do not understand your command.")
	}
}

func jsonResp(w http.ResponseWriter, x *jsonData) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")

	attachments := make([]Attachments, len(x.Data))
	for i := 0; i < len(x.Data); i++ {
		attachments[i] = Attachments{
			Title:      x.Data[i].Caption,
			Title_link: x.Data[i].Link,
			Thumb_url:  x.Data[i].Images.Small,
		}
	}

	resp := Response{
		Text:        "lorem ipsum",
		Attachments: attachments,
	}

	r, err := json.Marshal(resp)
	if err != nil {
		fmt.Println("Couldn't marshal hook response:", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	w.Write(r)
}
<commit_msg>Handle command for sections and subsections.<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"strings"
)

type Response struct {
	Text        string        `json:"text"`
	Attachments []Attachments `json:"attachments"`
}

type Attachments struct {
	Title      string `json:"title"`
	Title_link string `json:"title_link"`
	Thumb_url  string `json:"thumb_url"`
}

type jsonData struct {
	Status  int64
	Message string
	Data    []Data
}

type Data struct {
	Id      string
	Caption string
	Images  struct {
		Small  string
		Cover  string
		Normal string
		Large  string
	}
	Media interface{}
	Link  string
	Votes struct {
		Count int64
	}
	Comments struct {
		Count int64
	}
}

func main() {
	http.HandleFunc("/", handler)
	fmt.Println("listening...")
	err := http.ListenAndServe(":"+os.Getenv("PORT"), nil)
	if err != nil {
		panic(err)
	}
}

func handler(w http.ResponseWriter, r *http.Request) {

	url := "http://infinigag.k3min.eu"
	// Read the Request Parameter "command"
	command := r.FormValue("command")

	if command == "/9gag" {
		// Read the Request Parameter "text"
		text := r.FormValue("text")
		s := strings.Split(text, " ")
		var section string
		var subsection string
		if len(s) == 2 {
			section = s[0]
			subsection = s[1]
		} else if len(s) == 1 {
			section = s[0]
		}
		switch section {
		case "cute":
			url += "/cute"
		case "cosplay":
			url += "/cosplay"
		case "design":
			url += "/design"
		case "food":
			url += "/food"
		case "funny":
			url += "/funny"
		case "geeky":
			url += "/geeky"
		case "gif":
			url += "/gif"
		case "girl":
			url += "/girl"
		case "meme":
			url += "/meme"
		case "nsfw":
			url += "/nsfw"
		case "timely":
			url += "/timely"
		case "wtf":
			url += "/wtf"
		}

		switch subsection {
		case "fresh":
			url += "/fresh"
		case "trending":
			url += "trending"
		}

		fmt.Println(url)
		r, err := http.Get(url)
		if err != nil {
			fmt.Println("Error requesting data")
			return
		}
		body, err := ioutil.ReadAll(r.Body)
		if err != nil {
			fmt.Println("Error while opening file", err)
			return
		}
		x := new(jsonData)
		err = json.Unmarshal(body, &x)
		if err != nil {
			fmt.Println("Error while parsing file", err)
			return
		}
		jsonResp(w, x)
	} else {
		fmt.Fprint(w, "I do not understand your command.")
	}
}

func jsonResp(w http.ResponseWriter, x *jsonData) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")

	attachments := make([]Attachments, len(x.Data))
	for i := 0; i < len(x.Data); i++ {
		attachments[i] = Attachments{
			Title:      x.Data[i].Caption,
			Title_link: x.Data[i].Link,
			Thumb_url:  x.Data[i].Images.Small,
		}
	}

	resp := Response{
		Text:        "lorem ipsum",
		Attachments: attachments,
	}

	r, err := json.Marshal(resp)
	if err != nil {
		fmt.Println("Couldn't marshal hook response:", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	w.Write(r)
}
<|endoftext|>