<commit_before>package aws

import (
	"fmt"
	"log"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
	"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
)

func resourceAwsEc2ClientVpnEndpoint() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsEc2ClientVpnEndpointCreate,
		Read:   resourceAwsEc2ClientVpnEndpointRead,
		Delete: resourceAwsEc2ClientVpnEndpointDelete,
		Update: resourceAwsEc2ClientVpnEndpointUpdate,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"description": {
				Type:     schema.TypeString,
				Optional: true,
			},
			"client_cidr_block": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"dns_servers": {
				Type:     schema.TypeSet,
				Optional: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
			},
			"server_certificate_arn": {
				Type:     schema.TypeString,
				Required: true,
			},
			"split_tunnel": {
				Type:     schema.TypeBool,
				Optional: true,
				Default:  false,
			},
			"transport_protocol": {
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
				Default:  ec2.TransportProtocolUdp,
				ValidateFunc: validation.StringInSlice([]string{
					ec2.TransportProtocolTcp,
					ec2.TransportProtocolUdp,
				}, false),
			},
			"authentication_options": {
				Type:     schema.TypeList,
				Required: true,
				MaxItems: 1,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"type": {
							Type:     schema.TypeString,
							Required: true,
							ForceNew: true,
							ValidateFunc: validation.StringInSlice([]string{
								ec2.ClientVpnAuthenticationTypeCertificateAuthentication,
								ec2.ClientVpnAuthenticationTypeDirectoryServiceAuthentication,
							}, false),
						},
						"active_directory_id": {
							Type:     schema.TypeString,
							Optional: true,
							ForceNew: true,
						},
						"root_certificate_chain_arn": {
							Type:     schema.TypeString,
							Optional: true,
							ForceNew: true,
						},
					},
				},
			},
			"connection_log_options": {
				Type:     schema.TypeList,
				Required: true,
				MaxItems: 1,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"cloudwatch_log_group": {
							Type:     schema.TypeString,
							Optional: true,
						},
						"cloudwatch_log_stream": {
							Type:     schema.TypeString,
							Optional: true,
						},
						"enabled": {
							Type:     schema.TypeBool,
							Required: true,
						},
					},
				},
			},
			"dns_name": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"status": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"tags": tagsSchema(),
		},
	}
}

func resourceAwsEc2ClientVpnEndpointCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn

	req := &ec2.CreateClientVpnEndpointInput{
		ClientCidrBlock:      aws.String(d.Get("client_cidr_block").(string)),
		ServerCertificateArn: aws.String(d.Get("server_certificate_arn").(string)),
		TransportProtocol:    aws.String(d.Get("transport_protocol").(string)),
		SplitTunnel:          aws.Bool(d.Get("split_tunnel").(bool)),
		TagSpecifications:    ec2TagSpecificationsFromMap(d.Get("tags").(map[string]interface{}), ec2.ResourceTypeClientVpnEndpoint),
	}

	if v, ok := d.GetOk("description"); ok {
		req.Description = aws.String(v.(string))
	}

	if v, ok := d.GetOk("dns_servers"); ok {
		req.DnsServers = expandStringList(v.(*schema.Set).List())
	}

	if v, ok := d.GetOk("authentication_options"); ok {
		authOptsSet := v.([]interface{})
		attrs := authOptsSet[0].(map[string]interface{})

		authOptsReq := &ec2.ClientVpnAuthenticationRequest{
			Type: aws.String(attrs["type"].(string)),
		}

		if attrs["type"].(string) == "certificate-authentication" {
			authOptsReq.MutualAuthentication = &ec2.CertificateAuthenticationRequest{
				ClientRootCertificateChainArn: aws.String(attrs["root_certificate_chain_arn"].(string)),
			}
		}

		if attrs["type"].(string) == "directory-service-authentication" {
			authOptsReq.ActiveDirectory = &ec2.DirectoryServiceAuthenticationRequest{
				DirectoryId: aws.String(attrs["active_directory_id"].(string)),
			}
		}

		req.AuthenticationOptions = []*ec2.ClientVpnAuthenticationRequest{authOptsReq}
	}

	if v, ok := d.GetOk("connection_log_options"); ok {
		connLogSet := v.([]interface{})
		attrs := connLogSet[0].(map[string]interface{})

		connLogReq := &ec2.ConnectionLogOptions{
			Enabled: aws.Bool(attrs["enabled"].(bool)),
		}

		if attrs["enabled"].(bool) && attrs["cloudwatch_log_group"].(string) != "" {
			connLogReq.CloudwatchLogGroup = aws.String(attrs["cloudwatch_log_group"].(string))
		}

		if attrs["enabled"].(bool) && attrs["cloudwatch_log_stream"].(string) != "" {
			connLogReq.CloudwatchLogStream = aws.String(attrs["cloudwatch_log_stream"].(string))
		}

		req.ConnectionLogOptions = connLogReq
	}

	resp, err := conn.CreateClientVpnEndpoint(req)

	if err != nil {
		return fmt.Errorf("Error creating Client VPN endpoint: %s", err)
	}

	d.SetId(*resp.ClientVpnEndpointId)

	return resourceAwsEc2ClientVpnEndpointRead(d, meta)
}

func resourceAwsEc2ClientVpnEndpointRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn
	var err error

	result, err := conn.DescribeClientVpnEndpoints(&ec2.DescribeClientVpnEndpointsInput{
		ClientVpnEndpointIds: []*string{aws.String(d.Id())},
	})

	if isAWSErr(err, "InvalidClientVpnAssociationId.NotFound", "") || isAWSErr(err, "InvalidClientVpnEndpointId.NotFound", "") {
		log.Printf("[WARN] EC2 Client VPN Endpoint (%s) not found, removing from state", d.Id())
		d.SetId("")
		return nil
	}

	if err != nil {
		return fmt.Errorf("Error reading Client VPN endpoint: %s", err)
	}

	if result == nil || len(result.ClientVpnEndpoints) == 0 || result.ClientVpnEndpoints[0] == nil {
		log.Printf("[WARN] EC2 Client VPN Endpoint (%s) not found, removing from state", d.Id())
		d.SetId("")
		return nil
	}

	if result.ClientVpnEndpoints[0].Status != nil && aws.StringValue(result.ClientVpnEndpoints[0].Status.Code) == ec2.ClientVpnEndpointStatusCodeDeleted {
		log.Printf("[WARN] EC2 Client VPN Endpoint (%s) not found, removing from state", d.Id())
		d.SetId("")
		return nil
	}

	d.Set("description", result.ClientVpnEndpoints[0].Description)
	d.Set("client_cidr_block", result.ClientVpnEndpoints[0].ClientCidrBlock)
	d.Set("server_certificate_arn", result.ClientVpnEndpoints[0].ServerCertificateArn)
	d.Set("transport_protocol", result.ClientVpnEndpoints[0].TransportProtocol)
	d.Set("dns_name", result.ClientVpnEndpoints[0].DnsName)
	d.Set("dns_servers", result.ClientVpnEndpoints[0].DnsServers)

	if result.ClientVpnEndpoints[0].Status != nil {
		d.Set("status", result.ClientVpnEndpoints[0].Status.Code)
	}

	d.Set("split_tunnel", result.ClientVpnEndpoints[0].SplitTunnel)

	err = d.Set("authentication_options", flattenAuthOptsConfig(result.ClientVpnEndpoints[0].AuthenticationOptions))
	if err != nil {
		return fmt.Errorf("error setting authentication_options: %s", err)
	}

	err = d.Set("connection_log_options", flattenConnLoggingConfig(result.ClientVpnEndpoints[0].ConnectionLogOptions))
	if err != nil {
		return fmt.Errorf("error setting connection_log_options: %s", err)
	}

	err = d.Set("tags", tagsToMap(result.ClientVpnEndpoints[0].Tags))
	if err != nil {
		return fmt.Errorf("error setting tags: %s", err)
	}

	return nil
}

func resourceAwsEc2ClientVpnEndpointDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn

	_, err := conn.DeleteClientVpnEndpoint(&ec2.DeleteClientVpnEndpointInput{
		ClientVpnEndpointId: aws.String(d.Id()),
	})
	if err != nil {
		return fmt.Errorf("Error deleting Client VPN endpoint: %s", err)
	}

	return nil
}

func resourceAwsEc2ClientVpnEndpointUpdate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn

	d.Partial(true)

	req := &ec2.ModifyClientVpnEndpointInput{
		ClientVpnEndpointId: aws.String(d.Id()),
	}

	if d.HasChange("description") {
		req.Description = aws.String(d.Get("description").(string))
	}

	if d.HasChange("dns_servers") {
		dnsValue := expandStringList(d.Get("dns_servers").(*schema.Set).List())
		var enabledValue *bool

		if len(dnsValue) > 0 {
			enabledValue = aws.Bool(true)
		} else {
			enabledValue = aws.Bool(false)
		}

		dnsMod := &ec2.DnsServersOptionsModifyStructure{
			CustomDnsServers: dnsValue,
			Enabled:          enabledValue,
		}
		req.DnsServers = dnsMod
	}

	if d.HasChange("server_certificate_arn") {
		req.ServerCertificateArn = aws.String(d.Get("server_certificate_arn").(string))
	}

	if d.HasChange("split_tunnel") {
		req.SplitTunnel = aws.Bool(d.Get("split_tunnel").(bool))
	}

	if d.HasChange("connection_log_options") {
		if v, ok := d.GetOk("connection_log_options"); ok {
			connSet := v.([]interface{})
			attrs := connSet[0].(map[string]interface{})

			connReq := &ec2.ConnectionLogOptions{
				Enabled: aws.Bool(attrs["enabled"].(bool)),
			}

			if attrs["enabled"].(bool) && attrs["cloudwatch_log_group"].(string) != "" {
				connReq.CloudwatchLogGroup = aws.String(attrs["cloudwatch_log_group"].(string))
			}

			if attrs["enabled"].(bool) && attrs["cloudwatch_log_stream"].(string) != "" {
				connReq.CloudwatchLogStream = aws.String(attrs["cloudwatch_log_stream"].(string))
			}

			req.ConnectionLogOptions = connReq
		}
	}

	if _, err := conn.ModifyClientVpnEndpoint(req); err != nil {
		return fmt.Errorf("Error modifying Client VPN endpoint: %s", err)
	}

	if err := setTags(conn, d); err != nil {
		return err
	}
	d.SetPartial("tags")

	d.Partial(false)
	return resourceAwsEc2ClientVpnEndpointRead(d, meta)
}

func flattenConnLoggingConfig(lopts *ec2.ConnectionLogResponseOptions) []map[string]interface{} {
	m := make(map[string]interface{})
	if lopts.CloudwatchLogGroup != nil {
		m["cloudwatch_log_group"] = *lopts.CloudwatchLogGroup
	}
	if lopts.CloudwatchLogStream != nil {
		m["cloudwatch_log_stream"] = *lopts.CloudwatchLogStream
	}
	m["enabled"] = *lopts.Enabled
	return []map[string]interface{}{m}
}

func flattenAuthOptsConfig(aopts []*ec2.ClientVpnAuthentication) []map[string]interface{} {
	m := make(map[string]interface{})
	if aopts[0].MutualAuthentication != nil {
		m["root_certificate_chain_arn"] = *aopts[0].MutualAuthentication.ClientRootCertificateChain
	}
	if aopts[0].ActiveDirectory != nil {
		m["active_directory_id"] = *aopts[0].ActiveDirectory.DirectoryId
	}
	m["type"] = *aopts[0].Type
	return []map[string]interface{}{m}
}
<commit_msg>resource/aws_ec2_client_vpn_endpoint: Refactor to use keyvaluetags package (#11917)<commit_after>package aws

import (
	"fmt"
	"log"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
	"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
	"github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags"
)

func resourceAwsEc2ClientVpnEndpoint() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsEc2ClientVpnEndpointCreate,
		Read:   resourceAwsEc2ClientVpnEndpointRead,
		Delete: resourceAwsEc2ClientVpnEndpointDelete,
		Update: resourceAwsEc2ClientVpnEndpointUpdate,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"description": {
				Type:     schema.TypeString,
				Optional: true,
			},
			"client_cidr_block": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"dns_servers": {
				Type:     schema.TypeSet,
				Optional: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
			},
			"server_certificate_arn": {
				Type:     schema.TypeString,
				Required: true,
			},
			"split_tunnel": {
				Type:     schema.TypeBool,
				Optional: true,
				Default:  false,
			},
			"transport_protocol": {
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
				Default:  ec2.TransportProtocolUdp,
				ValidateFunc: validation.StringInSlice([]string{
					ec2.TransportProtocolTcp,
					ec2.TransportProtocolUdp,
				}, false),
			},
			"authentication_options": {
				Type:     schema.TypeList,
				Required: true,
				MaxItems: 1,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"type": {
							Type:     schema.TypeString,
							Required: true,
							ForceNew: true,
							ValidateFunc: validation.StringInSlice([]string{
								ec2.ClientVpnAuthenticationTypeCertificateAuthentication,
								ec2.ClientVpnAuthenticationTypeDirectoryServiceAuthentication,
							}, false),
						},
						"active_directory_id": {
							Type:     schema.TypeString,
							Optional: true,
							ForceNew: true,
						},
						"root_certificate_chain_arn": {
							Type:     schema.TypeString,
							Optional: true,
							ForceNew: true,
						},
					},
				},
			},
			"connection_log_options": {
				Type:     schema.TypeList,
				Required: true,
				MaxItems: 1,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"cloudwatch_log_group": {
							Type:     schema.TypeString,
							Optional: true,
						},
						"cloudwatch_log_stream": {
							Type:     schema.TypeString,
							Optional: true,
						},
						"enabled": {
							Type:     schema.TypeBool,
							Required: true,
						},
					},
				},
			},
			"dns_name": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"status": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"tags": tagsSchema(),
		},
	}
}

func resourceAwsEc2ClientVpnEndpointCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn

	req := &ec2.CreateClientVpnEndpointInput{
		ClientCidrBlock:      aws.String(d.Get("client_cidr_block").(string)),
		ServerCertificateArn: aws.String(d.Get("server_certificate_arn").(string)),
		TransportProtocol:    aws.String(d.Get("transport_protocol").(string)),
		SplitTunnel:          aws.Bool(d.Get("split_tunnel").(bool)),
		TagSpecifications:    ec2TagSpecificationsFromMap(d.Get("tags").(map[string]interface{}), ec2.ResourceTypeClientVpnEndpoint),
	}

	if v, ok := d.GetOk("description"); ok {
		req.Description = aws.String(v.(string))
	}

	if v, ok := d.GetOk("dns_servers"); ok {
		req.DnsServers = expandStringList(v.(*schema.Set).List())
	}

	if v, ok := d.GetOk("authentication_options"); ok {
		authOptsSet := v.([]interface{})
		attrs := authOptsSet[0].(map[string]interface{})

		authOptsReq := &ec2.ClientVpnAuthenticationRequest{
			Type: aws.String(attrs["type"].(string)),
		}

		if attrs["type"].(string) == "certificate-authentication" {
			authOptsReq.MutualAuthentication = &ec2.CertificateAuthenticationRequest{
				ClientRootCertificateChainArn: aws.String(attrs["root_certificate_chain_arn"].(string)),
			}
		}

		if attrs["type"].(string) == "directory-service-authentication" {
			authOptsReq.ActiveDirectory = &ec2.DirectoryServiceAuthenticationRequest{
				DirectoryId: aws.String(attrs["active_directory_id"].(string)),
			}
		}

		req.AuthenticationOptions = []*ec2.ClientVpnAuthenticationRequest{authOptsReq}
	}

	if v, ok := d.GetOk("connection_log_options"); ok {
		connLogSet := v.([]interface{})
		attrs := connLogSet[0].(map[string]interface{})

		connLogReq := &ec2.ConnectionLogOptions{
			Enabled: aws.Bool(attrs["enabled"].(bool)),
		}

		if attrs["enabled"].(bool) && attrs["cloudwatch_log_group"].(string) != "" {
			connLogReq.CloudwatchLogGroup = aws.String(attrs["cloudwatch_log_group"].(string))
		}

		if attrs["enabled"].(bool) && attrs["cloudwatch_log_stream"].(string) != "" {
			connLogReq.CloudwatchLogStream = aws.String(attrs["cloudwatch_log_stream"].(string))
		}

		req.ConnectionLogOptions = connLogReq
	}

	resp, err := conn.CreateClientVpnEndpoint(req)

	if err != nil {
		return fmt.Errorf("Error creating Client VPN endpoint: %s", err)
	}

	d.SetId(*resp.ClientVpnEndpointId)

	return resourceAwsEc2ClientVpnEndpointRead(d, meta)
}

func resourceAwsEc2ClientVpnEndpointRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn
	var err error

	result, err := conn.DescribeClientVpnEndpoints(&ec2.DescribeClientVpnEndpointsInput{
		ClientVpnEndpointIds: []*string{aws.String(d.Id())},
	})

	if isAWSErr(err, "InvalidClientVpnAssociationId.NotFound", "") || isAWSErr(err, "InvalidClientVpnEndpointId.NotFound", "") {
		log.Printf("[WARN] EC2 Client VPN Endpoint (%s) not found, removing from state", d.Id())
		d.SetId("")
		return nil
	}

	if err != nil {
		return fmt.Errorf("Error reading Client VPN endpoint: %s", err)
	}

	if result == nil || len(result.ClientVpnEndpoints) == 0 || result.ClientVpnEndpoints[0] == nil {
		log.Printf("[WARN] EC2 Client VPN Endpoint (%s) not found, removing from state", d.Id())
		d.SetId("")
		return nil
	}

	if result.ClientVpnEndpoints[0].Status != nil && aws.StringValue(result.ClientVpnEndpoints[0].Status.Code) == ec2.ClientVpnEndpointStatusCodeDeleted {
		log.Printf("[WARN] EC2 Client VPN Endpoint (%s) not found, removing from state", d.Id())
		d.SetId("")
		return nil
	}

	d.Set("description", result.ClientVpnEndpoints[0].Description)
	d.Set("client_cidr_block", result.ClientVpnEndpoints[0].ClientCidrBlock)
	d.Set("server_certificate_arn", result.ClientVpnEndpoints[0].ServerCertificateArn)
	d.Set("transport_protocol", result.ClientVpnEndpoints[0].TransportProtocol)
	d.Set("dns_name", result.ClientVpnEndpoints[0].DnsName)
	d.Set("dns_servers", result.ClientVpnEndpoints[0].DnsServers)

	if result.ClientVpnEndpoints[0].Status != nil {
		d.Set("status", result.ClientVpnEndpoints[0].Status.Code)
	}

	d.Set("split_tunnel", result.ClientVpnEndpoints[0].SplitTunnel)

	err = d.Set("authentication_options", flattenAuthOptsConfig(result.ClientVpnEndpoints[0].AuthenticationOptions))
	if err != nil {
		return fmt.Errorf("error setting authentication_options: %s", err)
	}

	err = d.Set("connection_log_options", flattenConnLoggingConfig(result.ClientVpnEndpoints[0].ConnectionLogOptions))
	if err != nil {
		return fmt.Errorf("error setting connection_log_options: %s", err)
	}

	err = d.Set("tags", keyvaluetags.Ec2KeyValueTags(result.ClientVpnEndpoints[0].Tags).IgnoreAws().Map())
	if err != nil {
		return fmt.Errorf("error setting tags: %s", err)
	}

	return nil
}

func resourceAwsEc2ClientVpnEndpointDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn

	_, err := conn.DeleteClientVpnEndpoint(&ec2.DeleteClientVpnEndpointInput{
		ClientVpnEndpointId: aws.String(d.Id()),
	})
	if err != nil {
		return fmt.Errorf("Error deleting Client VPN endpoint: %s", err)
	}

	return nil
}

func resourceAwsEc2ClientVpnEndpointUpdate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn

	d.Partial(true)

	req := &ec2.ModifyClientVpnEndpointInput{
		ClientVpnEndpointId: aws.String(d.Id()),
	}

	if d.HasChange("description") {
		req.Description = aws.String(d.Get("description").(string))
	}

	if d.HasChange("dns_servers") {
		dnsValue := expandStringList(d.Get("dns_servers").(*schema.Set).List())
		var enabledValue *bool

		if len(dnsValue) > 0 {
			enabledValue = aws.Bool(true)
		} else {
			enabledValue = aws.Bool(false)
		}

		dnsMod := &ec2.DnsServersOptionsModifyStructure{
			CustomDnsServers: dnsValue,
			Enabled:          enabledValue,
		}
		req.DnsServers = dnsMod
	}

	if d.HasChange("server_certificate_arn") {
		req.ServerCertificateArn = aws.String(d.Get("server_certificate_arn").(string))
	}

	if d.HasChange("split_tunnel") {
		req.SplitTunnel = aws.Bool(d.Get("split_tunnel").(bool))
	}

	if d.HasChange("connection_log_options") {
		if v, ok := d.GetOk("connection_log_options"); ok {
			connSet := v.([]interface{})
			attrs := connSet[0].(map[string]interface{})

			connReq := &ec2.ConnectionLogOptions{
				Enabled: aws.Bool(attrs["enabled"].(bool)),
			}

			if attrs["enabled"].(bool) && attrs["cloudwatch_log_group"].(string) != "" {
				connReq.CloudwatchLogGroup = aws.String(attrs["cloudwatch_log_group"].(string))
			}

			if attrs["enabled"].(bool) && attrs["cloudwatch_log_stream"].(string) != "" {
				connReq.CloudwatchLogStream = aws.String(attrs["cloudwatch_log_stream"].(string))
			}

			req.ConnectionLogOptions = connReq
		}
	}

	if _, err := conn.ModifyClientVpnEndpoint(req); err != nil {
		return fmt.Errorf("Error modifying Client VPN endpoint: %s", err)
	}

	if d.HasChange("tags") {
		o, n := d.GetChange("tags")

		if err := keyvaluetags.Ec2UpdateTags(conn, d.Id(), o, n); err != nil {
			return fmt.Errorf("error updating EC2 Client VPN Endpoint (%s) tags: %s", d.Id(), err)
		}
	}

	d.Partial(false)
	return resourceAwsEc2ClientVpnEndpointRead(d, meta)
}

func flattenConnLoggingConfig(lopts *ec2.ConnectionLogResponseOptions) []map[string]interface{} {
	m := make(map[string]interface{})
	if lopts.CloudwatchLogGroup != nil {
		m["cloudwatch_log_group"] = *lopts.CloudwatchLogGroup
	}
	if lopts.CloudwatchLogStream != nil {
		m["cloudwatch_log_stream"] = *lopts.CloudwatchLogStream
	}
	m["enabled"] = *lopts.Enabled
	return []map[string]interface{}{m}
}

func flattenAuthOptsConfig(aopts []*ec2.ClientVpnAuthentication) []map[string]interface{} {
	m := make(map[string]interface{})
	if aopts[0].MutualAuthentication != nil {
		m["root_certificate_chain_arn"] = *aopts[0].MutualAuthentication.ClientRootCertificateChain
	}
	if aopts[0].ActiveDirectory != nil {
		m["active_directory_id"] = *aopts[0].ActiveDirectory.DirectoryId
	}
	m["type"] = *aopts[0].Type
	return []map[string]interface{}{m}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"encoding/hex"
	"fmt"
	"log"
	"net"
	"strings"

	"github.com/ogier/pflag"
	"github.com/superp00t/godog/phoxy"
)

const HOST = "cryptodog.ikrypto.club"

type Session struct {
	C net.Conn

	Nick string
	UF   *UserFrame

	Rdline *bufio.Reader
	B      *phoxy.PhoxyConn
}

func (s *Session) Wframe(f Frame) {
	s.C.Write(f.Serialize())
}

func (s *Session) SendAuthMsg() {
	fmt.Fprintf(s.C, ":%s 001 %s :Welcome to the Phoxy IRC bridge %s\n", HOST, s.Nick, s.Nick)
	fmt.Fprintf(s.C, ":%s MODE %s :+i\n", s.Nick, s.Nick)
}

func (s *Session) Notice(auth, msg string) {
	fr := &Frame{
		"NOTICE",
		auth,
		":***",
		msg,
	}
	s.C.Write(fr.Serialize())
}

func (s *Session) Authorized() {
	s.SendAuthMsg()

lp:
	for {
		str, err := s.Rdline.ReadString('\n')
		if err != nil {
			break
		}
		cmds := strings.Split(str, " ")
		switch cmds[0] {
		case "PING":
			fmt.Fprintf(s.C, ":%s PONG %s :%s\n", HOST, HOST, HOST)
		case "QUIT":
			break lp
		case "PRIVMSG":
			body := strings.Join(cmds[2:], " ")
			body = body[1 : len(body)-2]
			s.B.GroupMessage(body)
		case "JOIN":
			go func(cmd []string) {
				chatName := cmd[1][1:]
				chatName = chatName[:len(chatName)-1]
				realName := chatName
				endpoint := "https://ikrypto.club/phoxy/"

				typ := phoxy.PHOXY
				if strings.HasPrefix(chatName, "cd_") {
					realName = strings.TrimLeft(chatName, "cd_")
					typ = phoxy.BOSH
					endpoint = "https://crypto.dog/http-bind/"
				}

				Log(DEBUG, "Requested to join chat \"%s\"", chatName)
				var err error
				s.B, err = phoxy.New(&phoxy.Opts{
					Type:     typ,
					Username: s.Nick,
					Chatroom: realName,
					Endpoint: endpoint,
					APIKey:   "",
				})

				if err != nil {
					s.Notice("AUTH", err.Error())
					return
				}

				fp := hex.EncodeToString(s.B.Me.PublicKey[:])
				s.Notice("AUTH", "Your mpOTR fingerprint is "+fp)

				s.B.HandleFunc(phoxy.USERQUIT, func(ev *phoxy.Event) {
					fmt.Fprintf(s.C, ":%s!~_ QUIT :Quit: leaving\n", ev.Username)
				})

				s.B.HandleFunc(phoxy.USERJOIN, func(ev *phoxy.Event) {
					fmt.Fprintf(s.C, ":%s!~_ JOIN #%s\n", ev.Username, chatName)
				})

				s.B.HandleFunc(phoxy.GROUPMESSAGE, func(ev *phoxy.Event) {
					stre := strings.Split(ev.Body, "\n")
					for _, v := range stre {
						fmt.Fprintf(s.C, ":%s!~_ PRIVMSG #%s :%s\n", ev.Username, chatName, v)
					}
				})

				if err := s.B.Connect(); err != nil {
					s.Notice("AUTH", err.Error())
				}
			}(cmds)
		}

		Log(DEBUG, "Got auth string, %s", str)
	}

	if s.B != nil {
		s.B.Disconnect()
	}
}

func NewSession(c net.Conn) {
	s := &Session{
		C: c,
	}
	s.Notice("AUTH", "Hey")

	s.Rdline = bufio.NewReader(c)
	authFlags := 0

ml:
	for {
		str, err := s.Rdline.ReadString('\n')
		if err != nil {
			break
		}

		// Trim newline
		l := len(str) - 1
		char := str[:l]
		if char == "\n" {
			Log(DEBUG, "Removing newline")
			str = str[:l-1]
		}

		elements := strings.Split(str, " ")
		switch elements[0] {
		case "NICK":
			pNick := elements[1]
			pNick = pNick[:len(pNick)-2]
			s.Nick = pNick
			authFlags++
		case "USER":
			s.UF = DeserializeUserFrame(str)
			authFlags++
		case "QUIT":
			break ml
		default:
			log.Println("Unknown")
			break ml
		}

		Log(DEBUG, "Got data: %+v", s.UF)

		if authFlags == 2 {
			s.Authorized()
			return
		}
	}
	c.Close()
}

func main() {
	addrptr := pflag.StringP("listen", "l", ":6667", "The IP address to listen on")
	pflag.Parse()
	addr := *addrptr

	l, err := net.Listen("tcp", addr)
	if err != nil {
		log.Fatal(err)
	}

	for {
		c, err := l.Accept()
		if err != nil {
			continue
		}

		go NewSession(c)
	}
}
<commit_msg>don't break on unknown commands<commit_after>package main

import (
	"bufio"
	"encoding/hex"
	"fmt"
	"log"
	"net"
	"strings"

	"github.com/ogier/pflag"
	"github.com/superp00t/godog/phoxy"
)

const HOST = "cryptodog.ikrypto.club"

type Session struct {
	C net.Conn

	Nick string
	UF   *UserFrame

	Rdline *bufio.Reader
	B      *phoxy.PhoxyConn
}

func (s *Session) Wframe(f Frame) {
	s.C.Write(f.Serialize())
}

func (s *Session) SendAuthMsg() {
	fmt.Fprintf(s.C, ":%s 001 %s :Welcome to the Phoxy IRC bridge %s\n", HOST, s.Nick, s.Nick)
	fmt.Fprintf(s.C, ":%s MODE %s :+i\n", s.Nick, s.Nick)
}

func (s *Session) Notice(auth, msg string) {
	fr := &Frame{
		"NOTICE",
		auth,
		":***",
		msg,
	}
	s.C.Write(fr.Serialize())
}

func (s *Session) Authorized() {
	s.SendAuthMsg()

lp:
	for {
		str, err := s.Rdline.ReadString('\n')
		if err != nil {
			break
		}
		cmds := strings.Split(str, " ")
		switch cmds[0] {
		case "PING":
			fmt.Fprintf(s.C, ":%s PONG %s :%s\n", HOST, HOST, HOST)
		case "QUIT":
			break lp
		case "PRIVMSG":
			body := strings.Join(cmds[2:], " ")
			body = body[1 : len(body)-2]
			s.B.GroupMessage(body)
		case "JOIN":
			go func(cmd []string) {
				chatName := cmd[1][1:]
				chatName = chatName[:len(chatName)-1]
				realName := chatName
				endpoint := "https://ikrypto.club/phoxy/"

				typ := phoxy.PHOXY
				if strings.HasPrefix(chatName, "cd_") {
					realName = strings.TrimLeft(chatName, "cd_")
					typ = phoxy.BOSH
					endpoint = "https://crypto.dog/http-bind/"
				}

				Log(DEBUG, "Requested to join chat \"%s\"", chatName)
				var err error
				s.B, err = phoxy.New(&phoxy.Opts{
					Type:     typ,
					Username: s.Nick,
					Chatroom: realName,
					Endpoint: endpoint,
					APIKey:   "",
				})

				if err != nil {
					s.Notice("AUTH", err.Error())
					return
				}

				fp := hex.EncodeToString(s.B.Me.PublicKey[:])
				s.Notice("AUTH", "Your mpOTR fingerprint is "+fp)

				s.B.HandleFunc(phoxy.USERQUIT, func(ev *phoxy.Event) {
					fmt.Fprintf(s.C, ":%s!~_ QUIT :Quit: leaving\n", ev.Username)
				})

				s.B.HandleFunc(phoxy.USERJOIN, func(ev *phoxy.Event) {
					fmt.Fprintf(s.C, ":%s!~_ JOIN #%s\n", ev.Username, chatName)
				})

				s.B.HandleFunc(phoxy.GROUPMESSAGE, func(ev *phoxy.Event) {
					stre := strings.Split(ev.Body, "\n")
					for _, v := range stre {
						fmt.Fprintf(s.C, ":%s!~_ PRIVMSG #%s :%s\n", ev.Username, chatName, v)
					}
				})

				if err := s.B.Connect(); err != nil {
					s.Notice("AUTH", err.Error())
				}
			}(cmds)
		}

		Log(DEBUG, "Got auth string, %s", str)
	}

	if s.B != nil {
		s.B.Disconnect()
	}
}

func NewSession(c net.Conn) {
	s := &Session{
		C: c,
	}
	s.Notice("AUTH", "Hey")

	s.Rdline = bufio.NewReader(c)
	authFlags := 0

ml:
	for {
		str, err := s.Rdline.ReadString('\n')
		if err != nil {
			break
		}

		// Trim newline
		l := len(str) - 1
		char := str[:l]
		if char == "\n" {
			Log(DEBUG, "Removing newline")
			str = str[:l-1]
		}

		elements := strings.Split(str, " ")
		switch elements[0] {
		case "NICK":
			pNick := elements[1]
			pNick = pNick[:len(pNick)-2]
			s.Nick = pNick
			authFlags++
		case "USER":
			s.UF = DeserializeUserFrame(str)
			authFlags++
		case "QUIT":
			break ml
		default:
			log.Println("Unknown command", elements[0])
		}

		Log(DEBUG, "Got data: %+v", s.UF)

		if authFlags == 2 {
			s.Authorized()
			return
		}
	}
	c.Close()
}

func main() {
	addrptr := pflag.StringP("listen", "l", ":6667", "The IP address to listen on")
	pflag.Parse()
	addr := *addrptr

	l, err := net.Listen("tcp", addr)
	if err != nil {
		log.Fatal(err)
	}

	for {
		c, err := l.Accept()
		if err != nil {
			continue
		}

		go NewSession(c)
	}
}
<|endoftext|>


<commit_before>package terraform

import (
	"testing"

	"github.com/zclconf/go-cty/cty"
)

func TestSMCUserVariables(t *testing.T) {
	c := testModule(t, "smc-uservars")

	// Required variables not set
	diags := checkInputVariables(c.Module.Variables, nil)
	if !diags.HasErrors() {
		t.Fatal("check succeeded, but want errors")
	}

	// Required variables set, optional variables unset
	diags = checkInputVariables(c.Module.Variables, InputValues{
		"foo": &InputValue{
			Value:      cty.StringVal("bar"),
			SourceType: ValueFromCLIArg,
		},
	})
	if diags.HasErrors() {
		t.Fatalf("unexpected errors: %s", diags.Err())
	}

	// Mapping complete override
	diags = checkInputVariables(c.Module.Variables, InputValues{
		"foo": &InputValue{
			Value:      cty.StringVal("bar"),
			SourceType: ValueFromCLIArg,
		},
		"map": &InputValue{
			Value:      cty.StringVal("baz"),
			SourceType: ValueFromCLIArg,
		},
	})
	if !diags.HasErrors() {
		t.Fatal("check succeeded, but want errors")
	}

}
<commit_msg>core: fix tests for checkInputVariables<commit_after>package terraform

import (
	"testing"

	"github.com/zclconf/go-cty/cty"
)

func TestSMCUserVariables(t *testing.T) {
	c := testModule(t, "smc-uservars")

	// No variables set
	diags := checkInputVariables(c.Module.Variables, nil)
	if !diags.HasErrors() {
		t.Fatal("check succeeded, but want errors")
	}

	// Required variables set, optional variables unset
	// This is still an error at this layer, since it's the caller's
	// responsibility to have already merged in any default values.
	diags = checkInputVariables(c.Module.Variables, InputValues{
		"foo": &InputValue{
			Value:      cty.StringVal("bar"),
			SourceType: ValueFromCLIArg,
		},
	})
	if !diags.HasErrors() {
		t.Fatal("check succeeded, but want errors")
	}

	// All variables set
	diags = checkInputVariables(c.Module.Variables, InputValues{
		"foo": &InputValue{
			Value:      cty.StringVal("bar"),
			SourceType: ValueFromCLIArg,
		},
		"bar": &InputValue{
			Value:      cty.StringVal("baz"),
			SourceType: ValueFromCLIArg,
		},
		"map": &InputValue{
			Value:      cty.StringVal("baz"), // okay because config has no type constraint
			SourceType: ValueFromCLIArg,
		},
	})
	if diags.HasErrors() {
		//t.Fatal("check succeeded, but want errors")
		t.Fatalf("unexpected errors: %s", diags.Err())
	}
}
<|endoftext|>


<commit_before>/* walter: a deployment pipeline template
 * Copyright (C) 2014 Recruit Technologies Co., Ltd. and contributors
 * (see CONTRIBUTORS.md)
 *
 * 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 pipelines defines the pipeline and the resources.
package pipelines

import (
	"container/list"
	"fmt"

	"github.com/recruit-tech/walter/messengers"
	"github.com/recruit-tech/walter/services"
	"github.com/recruit-tech/walter/stages"
)

// Pipeline stores the list of stages.
type Pipeline struct {
	Stages list.List
}

// Resources stores the settings loaded from the configuation file.
type Resources struct {
	// Pipeline stores the list of stages to be executed.
	Pipeline *Pipeline

	// Cleanup stores the list of stages extecuted after Pipeline.
	Cleanup *Pipeline

	// Reporter stores the messenger client which report the result to the server.
	Reporter messengers.Messenger

	// RepoService is a client of VCS services such as GitHub and reports the result to the service.
	RepoService services.Service
}

// ReportStageResult throw the results of specified stage to the messenger services.
func (self *Resources) ReportStageResult(stage stages.Stage, resultStr string) {
	name := stage.GetStageName()
	if !self.Reporter.Suppress("result") {
		if resultStr == "true" {
			self.Reporter.Post(
				fmt.Sprintf("[%s][RESULT] Succeeded", name))
		} else if resultStr == "skipped" {
			self.Reporter.Post(
				fmt.Sprintf("[%s][RESULT] Skipped", name))
		} else {
			self.Reporter.Post(
				fmt.Sprintf("[%s][RESULT] Failed", name))
		}
	}

	if stage.GetStageOpts().ReportingFullOutput {
		if out := stage.GetOutResult(); (len(out) > 0) && (!self.Reporter.Suppress("stdout")) {
			self.Reporter.Post(
				fmt.Sprintf("[%s][STDOUT] %s", name, stage.GetOutResult()))
		}
		if err := stage.GetErrResult(); len(err) > 0 && (!self.Reporter.Suppress("stderr")) {
			self.Reporter.Post(
				fmt.Sprintf("[%s][STDERR] %s", name, stage.GetErrResult()))
		}
	}
}

// AddStage appends specified stage to the pipeline.
func (self *Pipeline) AddStage(stage stages.Stage) {
	self.Stages.PushBack(stage)
}

// Size returns the number of stages in the pipeline.
func (self *Pipeline) Size() int {
	return self.Stages.Len()
}

func (self *Pipeline) Build() {
	self.buildDeps(&self.Stages)
}

func (self *Pipeline) buildDeps(stages *list.List) {
}

func NewPipeline() *Pipeline {
	return &Pipeline{}
}
<commit_msg>golint changes pipeline.go<commit_after>/* walter: a deployment pipeline template
 * Copyright (C) 2014 Recruit Technologies Co., Ltd. and contributors
 * (see CONTRIBUTORS.md)
 *
 * 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 pipelines defines the pipeline and the resources.
package pipelines

import (
	"container/list"
	"fmt"

	"github.com/recruit-tech/walter/messengers"
	"github.com/recruit-tech/walter/services"
	"github.com/recruit-tech/walter/stages"
)

// Pipeline stores the list of stages.
type Pipeline struct {
	Stages list.List
}

// Resources stores the settings loaded from the configuation file.
type Resources struct {
	// Pipeline stores the list of stages to be executed.
	Pipeline *Pipeline

	// Cleanup stores the list of stages extecuted after Pipeline.
	Cleanup *Pipeline

	// Reporter stores the messenger client which report the result to the server.
	Reporter messengers.Messenger

	// RepoService is a client of VCS services such as GitHub and reports the result to the service.
	RepoService services.Service
}

// ReportStageResult throw the results of specified stage to the messenger services.
func (resources *Resources) ReportStageResult(stage stages.Stage, resultStr string) {
	name := stage.GetStageName()
	if !resources.Reporter.Suppress("result") {
		if resultStr == "true" {
			resources.Reporter.Post(
				fmt.Sprintf("[%s][RESULT] Succeeded", name))
		} else if resultStr == "skipped" {
			resources.Reporter.Post(
				fmt.Sprintf("[%s][RESULT] Skipped", name))
		} else {
			resources.Reporter.Post(
				fmt.Sprintf("[%s][RESULT] Failed", name))
		}
	}

	if stage.GetStageOpts().ReportingFullOutput {
		if out := stage.GetOutResult(); (len(out) > 0) && (!resources.Reporter.Suppress("stdout")) {
			resources.Reporter.Post(
				fmt.Sprintf("[%s][STDOUT] %s", name, stage.GetOutResult()))
		}
		if err := stage.GetErrResult(); len(err) > 0 && (!resources.Reporter.Suppress("stderr")) {
			resources.Reporter.Post(
				fmt.Sprintf("[%s][STDERR] %s", name, stage.GetErrResult()))
		}
	}
}

// AddStage appends specified stage to the pipeline.
func (resources *Pipeline) AddStage(stage stages.Stage) {
	resources.Stages.PushBack(stage)
}

// Size returns the number of stages in the pipeline.
func (resources *Pipeline) Size() int {
	return resources.Stages.Len()
}

//Build builds a pipeline for the current resources
func (resources *Pipeline) Build() {
	resources.buildDeps(&resources.Stages)
}

func (resources *Pipeline) buildDeps(stages *list.List) {
}

//NewPipeline create a new pipeline instance
func NewPipeline() *Pipeline {
	return &Pipeline{}
}
<|endoftext|>


<commit_before>package pipelines_test

import (
	"github.com/concourse/testflight/gitserver"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"
)

var _ = Describe("A job with a put that runs with no artifacts", func() {
	var originGitServer *gitserver.Server

	BeforeEach(func() {
		originGitServer = gitserver.Start(client)

		configurePipeline(
			"-c", "fixtures/put-only.yml",
			"-v", "origin-git-server="+originGitServer.URI(),
		)
	})

	AfterEach(func() {
		originGitServer.Stop()
	})

	It("has its working directory created anyway", func() {
		By("triggering the job")
		watch := triggerJob("broken-put")

		By("waiting for it to exit")
		<-watch.Exited

		By("asserting that it got past the 'cd' and tried to push from the bogus repository")
		Expect(watch).To(gbytes.Say("bogus: No such file or directory"))
		Expect(watch).To(gexec.Exit(1))
	})
})
<commit_msg>fix testflight compilation failures<commit_after>package pipelines_test

import (
	"github.com/concourse/testflight/gitserver"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"
)

var _ = Describe("A job with a put that runs with no artifacts", func() {
	var originGitServer *gitserver.Server

	BeforeEach(func() {
		originGitServer = gitserver.Start(client)

		flyHelper.ConfigurePipeline(
			pipelineName,
			"-c", "fixtures/put-only.yml",
			"-v", "origin-git-server="+originGitServer.URI(),
		)
	})

	AfterEach(func() {
		originGitServer.Stop()
	})

	It("has its working directory created anyway", func() {
		By("triggering the job")
		watch := flyHelper.TriggerJob(pipelineName, "broken-put")

		By("waiting for it to exit")
		<-watch.Exited

		By("asserting that it got past the 'cd' and tried to push from the bogus repository")
		Expect(watch).To(gbytes.Say("bogus: No such file or directory"))
		Expect(watch).To(gexec.Exit(1))
	})
})
<|endoftext|>


<commit_before>package main

import (
	"io"

	"github.com/Sirupsen/logrus"
)

// ToxicLinks are single direction pipelines that connects an input and output via
// a chain of toxics. There is a fixed number of toxics in the chain, such that a
// toxic always maps to the same toxic stub. Toxics are replaced with noops when
// disabled.
//
//         NoopToxic LatencyToxic  NoopToxic
//             v           v           v
// Input > ToxicStub > ToxicStub > ToxicStub > Output
//
type ToxicLink struct {
	stubs  []*ToxicStub
	proxy  *Proxy
	toxics *ToxicCollection
	input  *ChanWriter
	output *ChanReader
	closed chan struct{}
}

func NewToxicLink(proxy *Proxy, toxics *ToxicCollection) *ToxicLink {
	link := &ToxicLink{
		stubs:  make([]*ToxicStub, MaxToxics),
		proxy:  proxy,
		toxics: toxics,
		closed: make(chan struct{}),
	}

	// Initialize the link with ToxicStubs
	last := make(chan []byte)
	link.input = NewChanWriter(last)
	for i := 0; i < MaxToxics; i++ {
		next := make(chan []byte)
		link.stubs[i] = NewToxicStub(proxy, last, next)
		last = next
	}
	link.output = NewChanReader(last)
	return link
}

// Start the link with the specified toxics
func (link *ToxicLink) Start(name string, source io.Reader, dest io.WriteCloser) {
	go func() {
		bytes, err := io.Copy(link.input, source)
		if err != nil {
			logrus.WithFields(logrus.Fields{
				"name":     link.proxy.Name,
				"upstream": link.proxy.Upstream,
				"bytes":    bytes,
				"err":      err,
			}).Warn("Source terminated")
		}
		link.input.Close()
	}()
	for i, toxic := range link.toxics.toxics {
		go link.pipe(toxic, link.stubs[i])
	}
	go func() {
		defer close(link.closed)
		bytes, err := io.Copy(dest, link.output)
		if err != nil {
			logrus.WithFields(logrus.Fields{
				"name":     link.proxy.Name,
				"upstream": link.proxy.Upstream,
				"bytes":    bytes,
				"err":      err,
			}).Warn("Destination terminated")
		}
		dest.Close()
		link.toxics.RemoveLink(name)
		link.proxy.RemoveConnection(name)
	}()
}

func (link *ToxicLink) pipe(toxic Toxic, stub *ToxicStub) {
	if !toxic.Pipe(stub) {
		// If the toxic will not be restarted, unblock all writes to stub.interrupt
		// until the link is removed from the list.
		go func() {
			for {
				select {
				case <-stub.interrupt:
				case <-link.closed:
					return
				}
			}
		}()
	}
}

// Replace the toxic at the specified index
func (link *ToxicLink) SetToxic(toxic Toxic, index int) {
	link.stubs[index].Interrupt()
	go link.pipe(toxic, link.stubs[index])
}
<commit_msg>Clean up a bit more<commit_after>package main

import (
	"io"

	"github.com/Sirupsen/logrus"
)

// ToxicLinks are single direction pipelines that connects an input and output via
// a chain of toxics. There is a fixed number of toxics in the chain, such that a
// toxic always maps to the same toxic stub. Toxics are replaced with noops when
// disabled.
//
//         NoopToxic LatencyToxic  NoopToxic
//             v           v           v
// Input > ToxicStub > ToxicStub > ToxicStub > Output
//
type ToxicLink struct {
	stubs  []*ToxicStub
	proxy  *Proxy
	toxics *ToxicCollection
	input  *ChanWriter
	output *ChanReader
	closed chan struct{}
}

func NewToxicLink(proxy *Proxy, toxics *ToxicCollection) *ToxicLink {
	link := &ToxicLink{
		stubs:  make([]*ToxicStub, MaxToxics),
		proxy:  proxy,
		toxics: toxics,
		closed: make(chan struct{}),
	}

	// Initialize the link with ToxicStubs
	last := make(chan []byte)
	link.input = NewChanWriter(last)
	for i := 0; i < MaxToxics; i++ {
		next := make(chan []byte)
		link.stubs[i] = NewToxicStub(proxy, last, next)
		last = next
	}
	link.output = NewChanReader(last)
	return link
}

// Start the link with the specified toxics
func (link *ToxicLink) Start(name string, source io.Reader, dest io.WriteCloser) {
	go func() {
		bytes, err := io.Copy(link.input, source)
		if err != nil {
			logrus.WithFields(logrus.Fields{
				"name":     link.proxy.Name,
				"upstream": link.proxy.Upstream,
				"bytes":    bytes,
				"err":      err,
			}).Warn("Source terminated")
		}
		link.input.Close()
	}()
	for i, toxic := range link.toxics.toxics {
		go link.pipe(toxic, link.stubs[i])
	}
	go func() {
		defer close(link.closed)
		bytes, err := io.Copy(dest, link.output)
		if err != nil {
			logrus.WithFields(logrus.Fields{
				"name":     link.proxy.Name,
				"upstream": link.proxy.Upstream,
				"bytes":    bytes,
				"err":      err,
			}).Warn("Destination terminated")
		}
		dest.Close()
		link.toxics.RemoveLink(name)
		link.proxy.RemoveConnection(name)
	}()
}

func (link *ToxicLink) pipe(toxic Toxic, stub *ToxicStub) {
	if !toxic.Pipe(stub) {
		// If the toxic will not be restarted, unblock all writes to stub.interrupt
		// until the link is removed from the list.
		for {
			select {
			case <-stub.interrupt:
			case <-link.closed:
				return
			}
		}
	}
}

// Replace the toxic at the specified index
func (link *ToxicLink) SetToxic(toxic Toxic, index int) {
	link.stubs[index].Interrupt()
	go link.pipe(toxic, link.stubs[index])
}
<|endoftext|>


<commit_before>/*
 * host_test.go
 *
 * Copyright 2017 Bill Zissimopoulos
 */
/*
 * This file is part of Cgofuse.
 *
 * It is licensed under the MIT license. The full license text can be found
 * in the License.txt file at the root of this project.
 */

package fuse

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"testing"
	"time"
)

type testfs struct {
	FileSystemBase
	init, dstr int
}

func (self *testfs) Init() {
	self.init++
}

func (self *testfs) Destroy() {
	self.dstr++
}

func (self *testfs) Getattr(path string, stat *Stat_t, fh uint64) (errc int) {
	switch path {
	case "/":
		stat.Mode = S_IFDIR | 0555
		return 0
	default:
		return -ENOENT
	}
}

func (self *testfs) Readdir(path string,
	fill func(name string, stat *Stat_t, ofst int64) bool,
	ofst int64,
	fh uint64) (errc int) {
	fill(".", nil, 0)
	fill("..", nil, 0)
	return 0
}

func testHost(t *testing.T, unmount bool) {
	path, err := ioutil.TempDir("", "test")
	if nil != err {
		panic(err)
	}
	defer os.Remove(path)
	mntp := filepath.Join(path, "m")
	if "windows" != runtime.GOOS {
		err = os.Mkdir(mntp, os.FileMode(0755))
		if nil != err {
			panic(err)
		}
		defer os.Remove(mntp)
	}
	done := make(chan bool)
	tmch := time.After(3 * time.Second)
	tstf := &testfs{}
	host := NewFileSystemHost(tstf)
	mres := false
	ures := false
	go func() {
		mres = host.Mount([]string{"test", mntp})
		done <- true
	}()
	<-tmch
	if unmount {
		ures = host.Unmount()
	} else {
		ures = sendInterrupt()
	}
	<-done
	if !mres {
		t.Error("Mount failed")
	}
	if !ures {
		t.Error("Unmount failed")
	}
	if 1 != tstf.init {
		t.Errorf("Init() called %v times; expected 1", tstf.init)
	}
	if 1 != tstf.dstr {
		t.Errorf("Destroy() called %v times; expected 1", tstf.dstr)
	}
}

func TestUnmount(t *testing.T) {
	if "windows" != runtime.GOOS {
		testHost(t, true)
	}
}

func TestSignal(t *testing.T) {
	testHost(t, false)
}
<commit_msg>appveyor: do not call GenerateConsoleCtrlEvent as kills appveyor batch file<commit_after>/*
 * host_test.go
 *
 * Copyright 2017 Bill Zissimopoulos
 */
/*
 * This file is part of Cgofuse.
 *
 * It is licensed under the MIT license. The full license text can be found
 * in the License.txt file at the root of this project.
 */

package fuse

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"testing"
	"time"
)

type testfs struct {
	FileSystemBase
	init, dstr int
}

func (self *testfs) Init() {
	self.init++
}

func (self *testfs) Destroy() {
	self.dstr++
}

func (self *testfs) Getattr(path string, stat *Stat_t, fh uint64) (errc int) {
	switch path {
	case "/":
		stat.Mode = S_IFDIR | 0555
		return 0
	default:
		return -ENOENT
	}
}

func (self *testfs) Readdir(path string,
	fill func(name string, stat *Stat_t, ofst int64) bool,
	ofst int64,
	fh uint64) (errc int) {
	fill(".", nil, 0)
	fill("..", nil, 0)
	return 0
}

func testHost(t *testing.T, unmount bool) {
	path, err := ioutil.TempDir("", "test")
	if nil != err {
		panic(err)
	}
	defer os.Remove(path)
	mntp := filepath.Join(path, "m")
	if "windows" != runtime.GOOS {
		err = os.Mkdir(mntp, os.FileMode(0755))
		if nil != err {
			panic(err)
		}
		defer os.Remove(mntp)
	}
	done := make(chan bool)
	tmch := time.After(3 * time.Second)
	tstf := &testfs{}
	host := NewFileSystemHost(tstf)
	mres := false
	ures := false
	go func() {
		mres = host.Mount([]string{"test", mntp})
		done <- true
	}()
	<-tmch
	if unmount {
		ures = host.Unmount()
	} else {
		ures = sendInterrupt()
	}
	<-done
	if !mres {
		t.Error("Mount failed")
	}
	if !ures {
		t.Error("Unmount failed")
	}
	if 1 != tstf.init {
		t.Errorf("Init() called %v times; expected 1", tstf.init)
	}
	if 1 != tstf.dstr {
		t.Errorf("Destroy() called %v times; expected 1", tstf.dstr)
	}
}

func TestUnmount(t *testing.T) {
	testHost(t, true)
}

func TestSignal(t *testing.T) {
	if "windows" != runtime.GOOS {
		testHost(t, false)
	}
}
<|endoftext|>


<commit_before>package imgscale

import (
	"github.com/stretchr/testify/assert"
	"github.com/vanng822/imgscale/imagick"
	"path/filepath"
	"testing"
)

func TestGetImageWrongFile(t *testing.T) {
	path, _ := filepath.Abs("./data/")
	provider := imageProviderFile{path}

	filename := "kth.jpg"
	f := &Format{Prefix: "100x100", Height: 100, Ratio: 1.0, Thumbnail: true}
	info := &ImageInfo{filename, f, "jpg", ""}
	_, err := provider.Fetch(info.Filename)
	assert.Error(t, err)
}

func TestGetImageScaleOK(t *testing.T) {
	path, _ := filepath.Abs("./test_data/")
	provider := imageProviderFile{path}
	filename := "kth.jpg"
	f := &Format{Prefix: "133x100", Height: 100, Ratio: 0.0, Thumbnail: false}
	info := &ImageInfo{filename, f, "jpg", ""}
	img, err := provider.Fetch(info.Filename)
	defer img.Destroy()
	assert.Nil(t, err)
	err = ProcessImage(img, info)
	assert.Equal(t, 100, img.GetImageHeight())
	assert.Equal(t, 133, img.GetImageWidth())
	assert.Nil(t, err)
}

func TestGetImage100x100OK(t *testing.T) {
	path, _ := filepath.Abs("./test_data/")
	provider := NewImageProviderFile(path)
	filename := "kth.jpg"

	f := &Format{Prefix: "100x100", Height: 100, Ratio: 1.0, Thumbnail: true}
	info := &ImageInfo{filename, f, "jpg", ""}
	img, err := provider.Fetch(info.Filename)
	defer img.Destroy()
	assert.Nil(t, err)
	err = ProcessImage(img, info)
	assert.Equal(t, 100, img.GetImageHeight())
	assert.Equal(t, 100, img.GetImageWidth())
	assert.Nil(t, err)
}

func TestAutoRotate(t *testing.T) {
	path, _ := filepath.Abs("./test_data/")
	provider := NewImageProviderFile(path)
	filename := "kth.jpg"

	f := &Format{Prefix: "100x75", Height: 100, Ratio: 1.335, Thumbnail: true}
	info := &ImageInfo{filename, f, "jpg", ""}
	img, err := provider.Fetch(info.Filename)
	defer img.Destroy()
	assert.Nil(t, err)
	rotateOrientations := make([]imagick.OrientationType, 0)
	rotateOrientations = append(rotateOrientations, imagick.ORIENTATION_TOP_RIGHT)
	rotateOrientations = append(rotateOrientations, imagick.ORIENTATION_BOTTOM_RIGHT)
	rotateOrientations = append(rotateOrientations, imagick.ORIENTATION_BOTTOM_LEFT)
	rotateOrientations = append(rotateOrientations, imagick.ORIENTATION_RIGHT_TOP)
	rotateOrientations = append(rotateOrientations, imagick.ORIENTATION_LEFT_BOTTOM)
	rotateOrientations = append(rotateOrientations, imagick.ORIENTATION_TOP_LEFT)

	for _, orientation := range rotateOrientations {
		img.SetImageOrientation(orientation)
		err = AutoRotate(img)
		assert.Nil(t, err)
		assert.Equal(t, imagick.ORIENTATION_TOP_LEFT, img.GetImageOrientation())
	}

	noRotate := make([]imagick.OrientationType, 0)
	noRotate = append(noRotate, imagick.ORIENTATION_LEFT_TOP)
	noRotate = append(noRotate, imagick.ORIENTATION_UNDEFINED)
	noRotate = append(noRotate, imagick.ORIENTATION_RIGHT_BOTTOM)
	noRotate = append(noRotate, imagick.ORIENTATION_LEFT_TOP)

	for _, orientation := range noRotate {
		img.SetImageOrientation(orientation)
		err = AutoRotate(img)
		assert.Nil(t, err)
		assert.Equal(t, orientation, img.GetImageOrientation())
	}

}

func TestGetImageStrip(t *testing.T) {
	path, _ := filepath.Abs("./test_data/")
	provider := NewImageProviderFile(path)
	filename := "kth.jpg"
	f := &Format{Prefix: "original", Height: 0, Ratio: 0.0, Thumbnail: false, Strip: true}
	info := &ImageInfo{filename, f, "jpg", ""}
	img, err := provider.Fetch(info.Filename)
	defer img.Destroy()
	assert.Nil(t, err)
	originalLen := len(img.GetImageBlob())
	assert.Nil(t, ProcessImage(img, info))
	assert.True(t, originalLen > len(img.GetImageBlob()))
}

func TestGetImageQuality(t *testing.T) {
	path, _ := filepath.Abs("./test_data/")
	provider := NewImageProviderFile(path)
	filename := "kth.jpg"
	f := &Format{Prefix: "original", Height: 0, Ratio: 0.0, Thumbnail: false, Strip: false, Quality: 9}
	info := &ImageInfo{filename, f, "jpg", ""}
	img, err := provider.Fetch(info.Filename)
	defer img.Destroy()
	assert.Nil(t, err)
	originalLen := len(img.GetImageBlob())
	assert.Nil(t, ProcessImage(img, info))
	assert.True(t, originalLen > len(img.GetImageBlob()))
}<commit_msg>Test fix, uint can not longer compare with number (int)<commit_after>package imgscale

import (
	"github.com/stretchr/testify/assert"
	"github.com/vanng822/imgscale/imagick"
	"path/filepath"
	"testing"
)

func TestGetImageWrongFile(t *testing.T) {
	path, _ := filepath.Abs("./data/")
	provider := imageProviderFile{path}

	filename := "kth.jpg"
	f := &Format{Prefix: "100x100", Height: 100, Ratio: 1.0, Thumbnail: true}
	info := &ImageInfo{filename, f, "jpg", ""}
	_, err := provider.Fetch(info.Filename)
	assert.Error(t, err)
}

func TestGetImageScaleOK(t *testing.T) {
	path, _ := filepath.Abs("./test_data/")
	provider := imageProviderFile{path}
	filename := "kth.jpg"
	f := &Format{Prefix: "133x100", Height: 100, Ratio: 0.0, Thumbnail: false}
	info := &ImageInfo{filename, f, "jpg", ""}
	img, err := provider.Fetch(info.Filename)
	defer img.Destroy()
	assert.Nil(t, err)
	err = ProcessImage(img, info)
	assert.Equal(t, uint(100), img.GetImageHeight())
	assert.Equal(t, uint(133), img.GetImageWidth())
	assert.Nil(t, err)
}

func TestGetImage100x100OK(t *testing.T) {
	path, _ := filepath.Abs("./test_data/")
	provider := NewImageProviderFile(path)
	filename := "kth.jpg"

	f := &Format{Prefix: "100x100", Height: 100, Ratio: 1.0, Thumbnail: true}
	info := &ImageInfo{filename, f, "jpg", ""}
	img, err := provider.Fetch(info.Filename)
	defer img.Destroy()
	assert.Nil(t, err)
	err = ProcessImage(img, info)
	assert.Equal(t, uint(100), img.GetImageHeight())
	assert.Equal(t, uint(100), img.GetImageWidth())
	assert.Nil(t, err)
}

func TestAutoRotate(t *testing.T) {
	path, _ := filepath.Abs("./test_data/")
	provider := NewImageProviderFile(path)
	filename := "kth.jpg"

	f := &Format{Prefix: "100x75", Height: 100, Ratio: 1.335, Thumbnail: true}
	info := &ImageInfo{filename, f, "jpg", ""}
	img, err := provider.Fetch(info.Filename)
	defer img.Destroy()
	assert.Nil(t, err)
	rotateOrientations := make([]imagick.OrientationType, 0)
	rotateOrientations = append(rotateOrientations, imagick.ORIENTATION_TOP_RIGHT)
	rotateOrientations = append(rotateOrientations, imagick.ORIENTATION_BOTTOM_RIGHT)
	rotateOrientations = append(rotateOrientations, imagick.ORIENTATION_BOTTOM_LEFT)
	rotateOrientations = append(rotateOrientations, imagick.ORIENTATION_RIGHT_TOP)
	rotateOrientations = append(rotateOrientations, imagick.ORIENTATION_LEFT_BOTTOM)
	rotateOrientations = append(rotateOrientations, imagick.ORIENTATION_TOP_LEFT)

	for _, orientation := range rotateOrientations {
		img.SetImageOrientation(orientation)
		err = AutoRotate(img)
		assert.Nil(t, err)
		assert.Equal(t, imagick.ORIENTATION_TOP_LEFT, img.GetImageOrientation())
	}

	noRotate := make([]imagick.OrientationType, 0)
	noRotate = append(noRotate, imagick.ORIENTATION_LEFT_TOP)
	noRotate = append(noRotate, imagick.ORIENTATION_UNDEFINED)
	noRotate = append(noRotate, imagick.ORIENTATION_RIGHT_BOTTOM)
	noRotate = append(noRotate, imagick.ORIENTATION_LEFT_TOP)

	for _, orientation := range noRotate {
		img.SetImageOrientation(orientation)
		err = AutoRotate(img)
		assert.Nil(t, err)
		assert.Equal(t, orientation, img.GetImageOrientation())
	}

}

func TestGetImageStrip(t *testing.T) {
	path, _ := filepath.Abs("./test_data/")
	provider := NewImageProviderFile(path)
	filename := "kth.jpg"
	f := &Format{Prefix: "original", Height: 0, Ratio: 0.0, Thumbnail: false, Strip: true}
	info := &ImageInfo{filename, f, "jpg", ""}
	img, err := provider.Fetch(info.Filename)
	defer img.Destroy()
	assert.Nil(t, err)
	originalLen := len(img.GetImageBlob())
	assert.Nil(t, ProcessImage(img, info))
	assert.True(t, originalLen > len(img.GetImageBlob()))
}

func TestGetImageQuality(t *testing.T) {
	path, _ := filepath.Abs("./test_data/")
	provider := NewImageProviderFile(path)
	filename := "kth.jpg"
	f := &Format{Prefix: "original", Height: 0, Ratio: 0.0, Thumbnail: false, Strip: false, Quality: 9}
	info := &ImageInfo{filename, f, "jpg", ""}
	img, err := provider.Fetch(info.Filename)
	defer img.Destroy()
	assert.Nil(t, err)
	originalLen := len(img.GetImageBlob())
	assert.Nil(t, ProcessImage(img, info))
	assert.True(t, originalLen > len(img.GetImageBlob()))
}<|endoftext|>


<commit_before>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package common_test

import (
	gc "launchpad.net/gocheck"

	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/environs/imagemetadata"
	"launchpad.net/juju-core/environs/simplestreams"
	"launchpad.net/juju-core/provider/common"
	"launchpad.net/juju-core/testing/testbase"
)

type archSuite struct {
	testbase.LoggingSuite
}

var _ = gc.Suite(&archSuite{})

func (s *archSuite) setupMetadata(c *gc.C, arches []string) (environs.Environ, simplestreams.CloudSpec) {
	s.PatchValue(&imagemetadata.DefaultBaseURL, "")
	stor := newStorage(s, c)
	env := &mockEnviron{
		storage: stor,
		config:  configGetter(c),
	}

	var images []*imagemetadata.ImageMetadata
	for _, arch := range arches {
		images = append(images, &imagemetadata.ImageMetadata{
			Id:         "image-id",
			Arch:       arch,
			RegionName: "Region",
			Endpoint:   "https://endpoint/",
		})
	}
	// Append an image from another region with some other arch to ensure it is ignored.
	images = append(images, &imagemetadata.ImageMetadata{
		Id:         "image-id",
		Arch:       "arch",
		RegionName: "Region-Two",
		Endpoint:   "https://endpoint/",
	})
	cloudSpec := simplestreams.CloudSpec{
		Region:   "Region",
		Endpoint: "https://endpoint/",
	}
	err := imagemetadata.MergeAndWriteMetadata("precise", images, &cloudSpec, env.Storage())
	c.Assert(err, gc.IsNil)
	return env, cloudSpec
}

func (s *archSuite) TestSupportedArchitecturesNone(c *gc.C) {
	env, cloudSpec := s.setupMetadata(c, nil)
	imageConstraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{
		CloudSpec: cloudSpec,
	})
	arches, err := common.SupportedArchitectures(env, imageConstraint)
	c.Assert(err, gc.IsNil)
	c.Assert(arches, gc.HasLen, 0)
}

func (s *archSuite) TestSupportedArchitecturesOne(c *gc.C) {
	env, cloudSpec := s.setupMetadata(c, []string{"ppc64"})
	imageConstraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{
		CloudSpec: cloudSpec,
	})
	arches, err := common.SupportedArchitectures(env, imageConstraint)
	c.Assert(err, gc.IsNil)
	c.Assert(arches, gc.DeepEquals, []string{"ppc64"})
}

func (s *archSuite) TestSupportedArchitecturesMany(c *gc.C) {
	env, cloudSpec := s.setupMetadata(c, []string{"ppc64", "amd64"})
	imageConstraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{
		CloudSpec: cloudSpec,
	})
	arches, err := common.SupportedArchitectures(env, imageConstraint)
	c.Assert(err, gc.IsNil)
	c.Assert(arches, gc.DeepEquals, []string{"amd64", "ppc64"})
}
<commit_msg>fix lp 1305397<commit_after>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package common_test

import (
	gc "launchpad.net/gocheck"

	jc "github.com/juju/testing/checkers"

	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/environs/imagemetadata"
	"launchpad.net/juju-core/environs/simplestreams"
	"launchpad.net/juju-core/provider/common"
	"launchpad.net/juju-core/testing/testbase"
)

type archSuite struct {
	testbase.LoggingSuite
}

var _ = gc.Suite(&archSuite{})

func (s *archSuite) setupMetadata(c *gc.C, arches []string) (environs.Environ, simplestreams.CloudSpec) {
	s.PatchValue(&imagemetadata.DefaultBaseURL, "")
	stor := newStorage(s, c)
	env := &mockEnviron{
		storage: stor,
		config:  configGetter(c),
	}

	var images []*imagemetadata.ImageMetadata
	for _, arch := range arches {
		images = append(images, &imagemetadata.ImageMetadata{
			Id:         "image-id",
			Arch:       arch,
			RegionName: "Region",
			Endpoint:   "https://endpoint/",
		})
	}
	// Append an image from another region with some other arch to ensure it is ignored.
	images = append(images, &imagemetadata.ImageMetadata{
		Id:         "image-id",
		Arch:       "arch",
		RegionName: "Region-Two",
		Endpoint:   "https://endpoint/",
	})
	cloudSpec := simplestreams.CloudSpec{
		Region:   "Region",
		Endpoint: "https://endpoint/",
	}
	err := imagemetadata.MergeAndWriteMetadata("precise", images, &cloudSpec, env.Storage())
	c.Assert(err, gc.IsNil)
	return env, cloudSpec
}

func (s *archSuite) TestSupportedArchitecturesNone(c *gc.C) {
	env, cloudSpec := s.setupMetadata(c, nil)
	imageConstraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{
		CloudSpec: cloudSpec,
	})
	arches, err := common.SupportedArchitectures(env, imageConstraint)
	c.Assert(err, gc.IsNil)
	c.Assert(arches, gc.HasLen, 0)
}

func (s *archSuite) TestSupportedArchitecturesOne(c *gc.C) {
	env, cloudSpec := s.setupMetadata(c, []string{"ppc64"})
	imageConstraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{
		CloudSpec: cloudSpec,
	})
	arches, err := common.SupportedArchitectures(env, imageConstraint)
	c.Assert(err, gc.IsNil)
	c.Assert(arches, jc.SameContents, []string{"ppc64"})
}

func (s *archSuite) TestSupportedArchitecturesMany(c *gc.C) {
	env, cloudSpec := s.setupMetadata(c, []string{"ppc64", "amd64"})
	imageConstraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{
		CloudSpec: cloudSpec,
	})
	arches, err := common.SupportedArchitectures(env, imageConstraint)
	c.Assert(err, gc.IsNil)
	c.Assert(arches, jc.SameContents, []string{"amd64", "ppc64"})
}
<|endoftext|>


<commit_before>package add

import (
	"github.com/BytemarkHosting/bytemark-client/cmd/bytemark/app"
	"github.com/BytemarkHosting/bytemark-client/cmd/bytemark/app/args"
	"github.com/BytemarkHosting/bytemark-client/cmd/bytemark/app/flags"
	"github.com/BytemarkHosting/bytemark-client/cmd/bytemark/app/with"
	"github.com/BytemarkHosting/bytemark-client/cmd/bytemark/cliutil"
	"github.com/BytemarkHosting/bytemark-client/lib/brain"
	"github.com/BytemarkHosting/bytemark-client/lib/output/prettyprint"
	brainRequests "github.com/BytemarkHosting/bytemark-client/lib/requests/brain"
	"github.com/urfave/cli"
)

func init() {

	Commands = append(Commands, cli.Command{
		Name:      "vm default",
		Usage:     "adds a new VM default",
		UsageText: "--admin add vm default <default name>",
		Description: `adds a new VM Default to the current account, which can be specified as either public or private.
The server settings can be specified for the vm default with aditional flags

--default-name (and the <default name> positional argument) is an identifier for the default, not a default name for servers created based upon it.

A disc spec looks like the following: grade:size. The grade field is optional and will default to sata.
Multiple --disc flags can be used to add multiple discs to the VM Default

If --backup is set then a backup of the first disk will be taken at the
frequency specified - never, daily, weekly or monthly. If not specified the backup will default to weekly.`,
		Flags: cliutil.ConcatFlags(app.OutputFlags("vm default", "object"),
			flags.ImageInstallFlags, flags.ServerSpecFlags,
			[]cli.Flag{
				cli.StringFlag{
					Name:  "default-name",
					Usage: "The name of the VM default to add",
				},
				cli.BoolFlag{
					Name:  "public",
					Usage: "If the VM default should be made public or not",
				},
				cli.GenericFlag{
					Name:  "account",
					Usage: "the account to add the default to (will use 'bytemark' if unset)",
					Value: new(app.AccountNameFlag),
				},
			}),
		Action: app.Action(args.Optional("default-name"), with.RequiredFlags("default-name"), with.Auth, func(c *app.Context) (err error) {
			accountName := c.String("account")
			if !c.IsSet("account") {
				accountName = "bytemark"
			}
			account, err := c.Client().GetAccount(accountName)
			if err != nil {
				return
			}
			spec, err := flags.PrepareServerSpec(c, false)
			if err != nil {
				return
			}

			// time to unset some stuff that gets auto-set, if we didn't actually specify anything
			if !c.IsSet("disc") {
				spec.Discs = nil
			}
			if !c.IsSet("image") {
				spec.Reimage.Distribution = ""
			}
			if !c.IsSet("cores") {
				spec.VirtualMachine.Cores = 0
			}
			if !c.IsSet("memory") {
				spec.VirtualMachine.Memory = 0
			}
			spec.VirtualMachine.Autoreboot = false

			vmd := brain.VirtualMachineDefault{
				AccountID:      account.BrainID,
				Name:           c.String("default-name"),
				Public:         c.Bool("public"),
				ServerSettings: spec,
			}

			vmd, err = brainRequests.CreateVMDefault(c.Client(), vmd)
			if err != nil {
				return
			}
			c.Log("Successfully created virtual machine default:")
			vmd.PrettyPrint(c.Writer(), prettyprint.Full)

			return
		}),
	})
}
<commit_msg>handle error returned by prettyprint if necessary<commit_after>package add

import (
	"github.com/BytemarkHosting/bytemark-client/cmd/bytemark/app"
	"github.com/BytemarkHosting/bytemark-client/cmd/bytemark/app/args"
	"github.com/BytemarkHosting/bytemark-client/cmd/bytemark/app/flags"
	"github.com/BytemarkHosting/bytemark-client/cmd/bytemark/app/with"
	"github.com/BytemarkHosting/bytemark-client/cmd/bytemark/cliutil"
	"github.com/BytemarkHosting/bytemark-client/lib/brain"
	"github.com/BytemarkHosting/bytemark-client/lib/output/prettyprint"
	brainRequests "github.com/BytemarkHosting/bytemark-client/lib/requests/brain"
	"github.com/urfave/cli"
)

func init() {

	Commands = append(Commands, cli.Command{
		Name:      "vm default",
		Usage:     "adds a new VM default",
		UsageText: "--admin add vm default <default name>",
		Description: `adds a new VM Default to the current account, which can be specified as either public or private.
The server settings can be specified for the vm default with aditional flags

--default-name (and the <default name> positional argument) is an identifier for the default, not a default name for servers created based upon it.

A disc spec looks like the following: grade:size. The grade field is optional and will default to sata.
Multiple --disc flags can be used to add multiple discs to the VM Default

If --backup is set then a backup of the first disk will be taken at the
frequency specified - never, daily, weekly or monthly. If not specified the backup will default to weekly.`,
		Flags: cliutil.ConcatFlags(app.OutputFlags("vm default", "object"),
			flags.ImageInstallFlags, flags.ServerSpecFlags,
			[]cli.Flag{
				cli.StringFlag{
					Name:  "default-name",
					Usage: "The name of the VM default to add",
				},
				cli.BoolFlag{
					Name:  "public",
					Usage: "If the VM default should be made public or not",
				},
				cli.GenericFlag{
					Name:  "account",
					Usage: "the account to add the default to (will use 'bytemark' if unset)",
					Value: new(app.AccountNameFlag),
				},
			}),
		Action: app.Action(args.Optional("default-name"), with.RequiredFlags("default-name"), with.Auth, func(c *app.Context) (err error) {
			accountName := c.String("account")
			if !c.IsSet("account") {
				accountName = "bytemark"
			}
			account, err := c.Client().GetAccount(accountName)
			if err != nil {
				return
			}
			spec, err := flags.PrepareServerSpec(c, false)
			if err != nil {
				return
			}

			// time to unset some stuff that gets auto-set, if we didn't actually specify anything
			if !c.IsSet("disc") {
				spec.Discs = nil
			}
			if !c.IsSet("image") {
				spec.Reimage.Distribution = ""
			}
			if !c.IsSet("cores") {
				spec.VirtualMachine.Cores = 0
			}
			if !c.IsSet("memory") {
				spec.VirtualMachine.Memory = 0
			}
			spec.VirtualMachine.Autoreboot = false

			vmd := brain.VirtualMachineDefault{
				AccountID:      account.BrainID,
				Name:           c.String("default-name"),
				Public:         c.Bool("public"),
				ServerSettings: spec,
			}

			vmd, err = brainRequests.CreateVMDefault(c.Client(), vmd)
			if err != nil {
				return
			}
			c.Log("Successfully created virtual machine default:")
			return vmd.PrettyPrint(c.Writer(), prettyprint.Full)
		}),
	})
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"

	"github.com/AsynkronIT/gam/actor"
	"github.com/AsynkronIT/goconsole"
)

type Hello struct{ Who string }
type HelloActor struct{}

func (state *HelloActor) Receive(context actor.Context) {
	switch msg := context.Message().(type) {
	case Hello:
		fmt.Printf("Hello %v\n", msg.Who)
	}
}

func main() {
	props := actor.FromInstance(&HelloActor{}).WithReceivePlugin(func(context actor.Context) interface{} {
		message := context.Message()
		fmt.Printf("Received message %v\n", message)
		return message
	})
	pid := actor.Spawn(props)
	pid.Tell(Hello{Who: "Roger"})
	console.ReadLine()
}
<commit_msg>formatting<commit_after>package main

import (
	"fmt"

	"github.com/AsynkronIT/gam/actor"
	"github.com/AsynkronIT/goconsole"
)

type Hello struct{ Who string }
type HelloActor struct{}

func (state *HelloActor) Receive(context actor.Context) {
	switch msg := context.Message().(type) {
	case Hello:
		fmt.Printf("Hello %v\n", msg.Who)
	}
}

func myReceivePlugin(context actor.Context) interface{} {
	message := context.Message()
	fmt.Printf("Received message %v\n", message)

	switch msg := context.Message().(type) {
	case Hello:
		return Hello{
			Who: msg.Who + " Modified",
		}
	}

	return message
}

func main() {
	props := actor.FromInstance(&HelloActor{}).WithReceivePlugin(myReceivePlugin)
	pid := actor.Spawn(props)
	pid.Tell(Hello{Who: "Roger"})
	console.ReadLine()
}
<|endoftext|>


<commit_before>package annotate

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"path/filepath"
	"sort"
	"strings"
	"testing"
	"text/template"
	"time"
	"unicode/utf8"
)

var saveExp = flag.Bool("exp", false, "overwrite all expected output files with actual output (returning a failure)")
var match = flag.String("m", "", "only run tests whose name contains this string")

func TestAnnotate(t *testing.T) {
	tests := map[string]struct {
		input   string
		anns    Annotations
		want    string
		wantErr error
	}{
		"empty and unannotated": {"", nil, "", nil},
		"unannotated":           {"a⌘b", nil, "a⌘b", nil},

		// The docs say "Annotating an empty byte array always returns an empty
		// byte array.", which is arbitrary but makes implementation easier.
		"empty annotated": {"", Annotations{{0, 0, []byte("["), []byte("]"), 0}}, "", nil},

		"zero-length annotations": {
			"aaaa",
			Annotations{
				{0, 0, []byte(""), []byte(""), 0},
				{0, 0, []byte(""), []byte(""), 0},
				{2, 2, []byte(""), []byte(""), 0},
			},
			"aaaa",
			nil,
		},
		"1 annotation": {"a", Annotations{{0, 1, []byte("["), []byte("]"), 0}}, "[a]", nil},
		"nested": {
			"abc",
			Annotations{
				{0, 3, []byte("["), []byte("]"), 0},
				{1, 2, []byte("<"), []byte(">"), 0},
			},
			"[ac]",
			nil,
		},
		"nested 1": {
			"abcd",
			Annotations{
				{0, 4, []byte("<1>"), []byte("</1>"), 0},
				{1, 3, []byte("<2>"), []byte("</2>"), 0},
				{2, 2, []byte("<3>"), []byte("</3>"), 0},
			},
			"<1>a<2>b<3></3>c</2>d</1>",
			nil,
		},
		"same range": {
			"ab",
			Annotations{
				{0, 2, []byte("["), []byte("]"), 0},
				{0, 2, []byte("<"), []byte(">"), 0},
			},
			"[<ab>]",
			nil,
		},
		"same range (with WantInner)": {
			"ab",
			Annotations{
				{0, 2, []byte("["), []byte("]"), 1},
				{0, 2, []byte("<"), []byte(">"), 0},
			},
			"<[ab]>",
			nil,
		},
		"unicode content": {
			"abcdef⌘vwxyz",
			Annotations{
				{6, 9, []byte(""), []byte(""), 0},
				{10, 12, []byte(""), []byte(""), 0},
				{0, 13, []byte("<c>"), []byte("</c>"), 0},
			},
			"<c>abcdef⌘vwxy</c>z",
			nil,
		},
		"remainder": {
			"xyz",
			Annotations{
				{0, 2, []byte(""), []byte(""), 0},
				{0, 1, []byte("<c>"), []byte("</c>"), 0},
			},
			"<c>x</c>yz",
			nil,
		},

		// Overlapping
		"overlap simple": {
			"abc",
			Annotations{
				{0, 2, []byte("<X>"), []byte("</X>"), 0},
				{1, 3, []byte("<Y>"), []byte("</Y>"), 0},
			},
			// Without re-opening overlapped annotations, we'd get
			// "<X>a<Y>b</X>c</Y>".
			"<X>a<Y>b</Y></X><Y>c</Y>",
			nil,
		},
		"overlap simple double": {
			"abc",
			Annotations{
				{0, 2, []byte("<X1>"), []byte("</X1>"), 0},
				{0, 2, []byte("<X2>"), []byte("</X2>"), 0},
				{1, 3, []byte("<Y1>"), []byte("</Y1>"), 0},
				{1, 3, []byte("<Y2>"), []byte("</Y2>"), 0},
			},
			"<X1><X2>a<Y1><Y2>b</Y2></Y1></X2></X1><Y1><Y2>c</Y2></Y1>",
			nil,
		},
		"overlap triple complex": {
			"abcd",
			Annotations{
				{0, 2, []byte("<X>"), []byte("</X>"), 0},
				{1, 3, []byte("<Y>"), []byte("</Y>"), 0},
				{2, 4, []byte("<Z>"), []byte("</Z>"), 0},
			},
			"<X>a<Y>b</Y></X><Y><Z>c</Z></Y><Z>d</Z>",
			nil,
		},
		"overlap same start": {
			"abcd",
			Annotations{
				{0, 2, []byte("<X>"), []byte("</X>"), 0},
				{0, 3, []byte("<Y>"), []byte("</Y>"), 0},
				{1, 4, []byte("<Z>"), []byte("</Z>"), 0},
			},
			"<Y><X>a<Z>b</Z></X><Z>c</Z></Y><Z>d</Z>",
			nil,
		},
		"overlap (infinite loop regression #1)": {
			"abcde",
			Annotations{
				{0, 3, []byte("<X>"), []byte("</X>"), 0},
				{1, 5, []byte("<Y>"), []byte("</Y>"), 0},
				{1, 2, []byte("<Z>"), []byte("</Z>"), 0},
			},
			"<X>a<Y><Z>b</Z>c</Y></X><Y>de</Y>",
			nil,
		},

		// Errors
		"start oob": {"a", Annotations{{-1, 1, []byte("<"), []byte(">"), 0}}, "", ErrStartOutOfBounds},
		"start oob (multiple)": {
			"a",
			Annotations{
				{-3, 1, []byte("1"), []byte(""), 0},
				{-3, 1, []byte("2"), []byte(""), 0},
				{-1, 1, []byte("3"), []byte(""), 0},
			},
			"123a",
			ErrStartOutOfBounds,
		},
		"end oob": {"a", Annotations{{0, 3, []byte("<"), []byte(">"), 0}}, "", ErrEndOutOfBounds},
		"end oob (multiple)": {
			"ab",
			Annotations{
				{0, 3, []byte(""), []byte("1"), 0},
				{1, 3, []byte(""), []byte("2"), 0},
				{0, 5, []byte(""), []byte("3"), 0},
			},
			"ab213",
			ErrEndOutOfBounds,
		},
	}
	for label, test := range tests {
		if *match != "" && !strings.Contains(label, *match) {
			continue
		}

		sort.Sort(Annotations(test.anns))

		got, err := Annotate([]byte(test.input), test.anns, nil)
		if err != test.wantErr {
			if test.wantErr == nil {
				t.Errorf("%s: Annotate: %s", label, err)
			} else {
				t.Errorf("%s: Annotate: got error %v, want %v", label, err, test.wantErr)
			}
		}
		if string(got) != test.want {
			t.Errorf("%s: Annotate:\ngot  %q\nwant %q", label, got, test.want)
			continue
		}
	}
}

func TestAnnotate_Files(t *testing.T) {
	annsByFile := map[string]Annotations{
		"hello_world.txt": Annotations{
			{0, 5, []byte(""), []byte(""), 0},
			{7, 12, []byte(""), []byte(""), 0},
		},
		"adjacent.txt": Annotations{
			{0, 3, []byte(""), []byte(""), 0},
			{3, 6, []byte(""), []byte(""), 0},
		},
		"nested_0.txt": Annotations{
			{0, 4, []byte("<1>"), []byte("</1>"), 0},
			{1, 3, []byte("<2>"), []byte("</2>"), 0},
		},
		"nested_2.txt": Annotations{
			{0, 2, []byte("<1>"), []byte("</1>"), 0},
			{2, 4, []byte("<2>"), []byte("</2>"), 0},
			{4, 6, []byte("<3>"), []byte("</3>"), 0},
			{7, 8, []byte("<4>"), []byte("</4>"), 0},
		},
		"html.txt": Annotations{
			{193, 203, []byte("<1>"), []byte("</1>"), 0},
			{336, 339, []byte("<WOOF>"), []byte("</WOOF>"), 0},
		},
	}

	dir := "testdata"
	tests, err := ioutil.ReadDir(dir)
	if err != nil {
		t.Fatal(err)
	}

	for _, test := range tests {
		name := test.Name()
		if !strings.Contains(name, *match) {
			continue
		}
		if strings.HasSuffix(name, ".html") {
			continue
		}
		path := filepath.Join(dir, name)
		input, err := ioutil.ReadFile(path)
		if err != nil {
			t.Fatal(err)
			continue
		}

		anns := annsByFile[name]
		sort.Sort(anns)

		got, err := Annotate(input, anns, template.HTMLEscape)
		if err != nil {
			t.Errorf("%s: Annotate: %s", name, err)
			continue
		}

		expPath := path + ".html"
		if *saveExp {
			err = ioutil.WriteFile(expPath, got, 0700)
			if err != nil {
				t.Fatal(err)
			}
			continue
		}

		want, err := ioutil.ReadFile(expPath)
		if err != nil {
			t.Fatal(err)
		}

		want = bytes.TrimSpace(want)
		got = bytes.TrimSpace(got)

		if !bytes.Equal(want, got) {
			t.Errorf("%s: want %q, got %q", name, want, got)
			continue
		}
	}

	if *saveExp {
		t.Fatal("overwrote all expected output files with actual output (run tests again without -exp)")
	}
}

func makeFakeData(size1, size2 int) ([]byte, Annotations) {
	input := []byte(strings.Repeat(strings.Repeat("a", size1)+"⌘", size2))
	inputLength := utf8.RuneCount(input)
	n := len(input)/2 - (size1+1)/2
	anns := make(Annotations, n)
	for i := 0; i < n; i++ {
		if i%2 == 0 {
			anns[i] = &Annotation{Start: 2 * i, End: 2*i + 1}
		} else {
			anns[i] = &Annotation{Start: 2*i - 50, End: 2*i + 50}
			if anns[i].Start < 0 {
				anns[i].Start = 0
				anns[i].End = i
			}
			if anns[i].End >= inputLength {
				anns[i].End = inputLength
			}
		}
		anns[i].Left = []byte("L")  //[]byte(strings.Repeat("L", i%20))
		anns[i].Right = []byte("R") //[]byte(strings.Repeat("R", i%20))
		anns[i].WantInner = i % 5
	}
	sort.Sort(anns)
	return input, anns
}

func TestAnnotate_GeneratedData(t *testing.T) {
	input, anns := makeFakeData(1, 15)

	fail := func(err error) {
		annStrs := make([]string, len(anns))
		for i, a := range anns {
			annStrs[i] = fmt.Sprintf("%v", a)
		}
		t.Fatalf("Annotate: %s\n\nInput was:\n%q\n\nAnnotations:\n%s", err, input, strings.Join(annStrs, "\n"))
	}

	tm := time.NewTimer(time.Millisecond * 500)
	done := make(chan error)

	go func() {
		_, err := Annotate(input, anns, nil)
		done <- err
	}()

	select {
	case <-tm.C:
		fail(errors.New("timed out (is there an infinite loop?)"))
	case err := <-done:
		if err != nil {
			fail(err)
		}
	}
}

func BenchmarkAnnotate(b *testing.B) {
	input, anns := makeFakeData(99, 20)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_, err := Annotate(input, anns, nil)
		if err != nil {
			b.Fatal(err)
		}
	}
}
<commit_msg>gofmt -s<commit_after>package annotate

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"path/filepath"
	"sort"
	"strings"
	"testing"
	"text/template"
	"time"
	"unicode/utf8"
)

var saveExp = flag.Bool("exp", false, "overwrite all expected output files with actual output (returning a failure)")
var match = flag.String("m", "", "only run tests whose name contains this string")

func TestAnnotate(t *testing.T) {
	tests := map[string]struct {
		input   string
		anns    Annotations
		want    string
		wantErr error
	}{
		"empty and unannotated": {"", nil, "", nil},
		"unannotated":           {"a⌘b", nil, "a⌘b", nil},

		// The docs say "Annotating an empty byte array always returns an empty
		// byte array.", which is arbitrary but makes implementation easier.
		"empty annotated": {"", Annotations{{0, 0, []byte("["), []byte("]"), 0}}, "", nil},

		"zero-length annotations": {
			"aaaa",
			Annotations{
				{0, 0, []byte(""), []byte(""), 0},
				{0, 0, []byte(""), []byte(""), 0},
				{2, 2, []byte(""), []byte(""), 0},
			},
			"aaaa",
			nil,
		},
		"1 annotation": {"a", Annotations{{0, 1, []byte("["), []byte("]"), 0}}, "[a]", nil},
		"nested": {
			"abc",
			Annotations{
				{0, 3, []byte("["), []byte("]"), 0},
				{1, 2, []byte("<"), []byte(">"), 0},
			},
			"[ac]",
			nil,
		},
		"nested 1": {
			"abcd",
			Annotations{
				{0, 4, []byte("<1>"), []byte("</1>"), 0},
				{1, 3, []byte("<2>"), []byte("</2>"), 0},
				{2, 2, []byte("<3>"), []byte("</3>"), 0},
			},
			"<1>a<2>b<3></3>c</2>d</1>",
			nil,
		},
		"same range": {
			"ab",
			Annotations{
				{0, 2, []byte("["), []byte("]"), 0},
				{0, 2, []byte("<"), []byte(">"), 0},
			},
			"[<ab>]",
			nil,
		},
		"same range (with WantInner)": {
			"ab",
			Annotations{
				{0, 2, []byte("["), []byte("]"), 1},
				{0, 2, []byte("<"), []byte(">"), 0},
			},
			"<[ab]>",
			nil,
		},
		"unicode content": {
			"abcdef⌘vwxyz",
			Annotations{
				{6, 9, []byte(""), []byte(""), 0},
				{10, 12, []byte(""), []byte(""), 0},
				{0, 13, []byte("<c>"), []byte("</c>"), 0},
			},
			"<c>abcdef⌘vwxy</c>z",
			nil,
		},
		"remainder": {
			"xyz",
			Annotations{
				{0, 2, []byte(""), []byte(""), 0},
				{0, 1, []byte("<c>"), []byte("</c>"), 0},
			},
			"<c>x</c>yz",
			nil,
		},

		// Overlapping
		"overlap simple": {
			"abc",
			Annotations{
				{0, 2, []byte("<X>"), []byte("</X>"), 0},
				{1, 3, []byte("<Y>"), []byte("</Y>"), 0},
			},
			// Without re-opening overlapped annotations, we'd get
			// "<X>a<Y>b</X>c</Y>".
			"<X>a<Y>b</Y></X><Y>c</Y>",
			nil,
		},
		"overlap simple double": {
			"abc",
			Annotations{
				{0, 2, []byte("<X1>"), []byte("</X1>"), 0},
				{0, 2, []byte("<X2>"), []byte("</X2>"), 0},
				{1, 3, []byte("<Y1>"), []byte("</Y1>"), 0},
				{1, 3, []byte("<Y2>"), []byte("</Y2>"), 0},
			},
			"<X1><X2>a<Y1><Y2>b</Y2></Y1></X2></X1><Y1><Y2>c</Y2></Y1>",
			nil,
		},
		"overlap triple complex": {
			"abcd",
			Annotations{
				{0, 2, []byte("<X>"), []byte("</X>"), 0},
				{1, 3, []byte("<Y>"), []byte("</Y>"), 0},
				{2, 4, []byte("<Z>"), []byte("</Z>"), 0},
			},
			"<X>a<Y>b</Y></X><Y><Z>c</Z></Y><Z>d</Z>",
			nil,
		},
		"overlap same start": {
			"abcd",
			Annotations{
				{0, 2, []byte("<X>"), []byte("</X>"), 0},
				{0, 3, []byte("<Y>"), []byte("</Y>"), 0},
				{1, 4, []byte("<Z>"), []byte("</Z>"), 0},
			},
			"<Y><X>a<Z>b</Z></X><Z>c</Z></Y><Z>d</Z>",
			nil,
		},
		"overlap (infinite loop regression #1)": {
			"abcde",
			Annotations{
				{0, 3, []byte("<X>"), []byte("</X>"), 0},
				{1, 5, []byte("<Y>"), []byte("</Y>"), 0},
				{1, 2, []byte("<Z>"), []byte("</Z>"), 0},
			},
			"<X>a<Y><Z>b</Z>c</Y></X><Y>de</Y>",
			nil,
		},

		// Errors
		"start oob": {"a", Annotations{{-1, 1, []byte("<"), []byte(">"), 0}}, "", ErrStartOutOfBounds},
		"start oob (multiple)": {
			"a",
			Annotations{
				{-3, 1, []byte("1"), []byte(""), 0},
				{-3, 1, []byte("2"), []byte(""), 0},
				{-1, 1, []byte("3"), []byte(""), 0},
			},
			"123a",
			ErrStartOutOfBounds,
		},
		"end oob": {"a", Annotations{{0, 3, []byte("<"), []byte(">"), 0}}, "", ErrEndOutOfBounds},
		"end oob (multiple)": {
			"ab",
			Annotations{
				{0, 3, []byte(""), []byte("1"), 0},
				{1, 3, []byte(""), []byte("2"), 0},
				{0, 5, []byte(""), []byte("3"), 0},
			},
			"ab213",
			ErrEndOutOfBounds,
		},
	}
	for label, test := range tests {
		if *match != "" && !strings.Contains(label, *match) {
			continue
		}

		sort.Sort(Annotations(test.anns))

		got, err := Annotate([]byte(test.input), test.anns, nil)
		if err != test.wantErr {
			if test.wantErr == nil {
				t.Errorf("%s: Annotate: %s", label, err)
			} else {
				t.Errorf("%s: Annotate: got error %v, want %v", label, err, test.wantErr)
			}
		}
		if string(got) != test.want {
			t.Errorf("%s: Annotate:\ngot  %q\nwant %q", label, got, test.want)
			continue
		}
	}
}

func TestAnnotate_Files(t *testing.T) {
	annsByFile := map[string]Annotations{
		"hello_world.txt": {
			{0, 5, []byte(""), []byte(""), 0},
			{7, 12, []byte(""), []byte(""), 0},
		},
		"adjacent.txt": {
			{0, 3, []byte(""), []byte(""), 0},
			{3, 6, []byte(""), []byte(""), 0},
		},
		"nested_0.txt": {
			{0, 4, []byte("<1>"), []byte("</1>"), 0},
			{1, 3, []byte("<2>"), []byte("</2>"), 0},
		},
		"nested_2.txt": {
			{0, 2, []byte("<1>"), []byte("</1>"), 0},
			{2, 4, []byte("<2>"), []byte("</2>"), 0},
			{4, 6, []byte("<3>"), []byte("</3>"), 0},
			{7, 8, []byte("<4>"), []byte("</4>"), 0},
		},
		"html.txt": {
			{193, 203, []byte("<1>"), []byte("</1>"), 0},
			{336, 339, []byte("<WOOF>"), []byte("</WOOF>"), 0},
		},
	}

	dir := "testdata"
	tests, err := ioutil.ReadDir(dir)
	if err != nil {
		t.Fatal(err)
	}

	for _, test := range tests {
		name := test.Name()
		if !strings.Contains(name, *match) {
			continue
		}
		if strings.HasSuffix(name, ".html") {
			continue
		}
		path := filepath.Join(dir, name)
		input, err := ioutil.ReadFile(path)
		if err != nil {
			t.Fatal(err)
			continue
		}

		anns := annsByFile[name]
		sort.Sort(anns)

		got, err := Annotate(input, anns, template.HTMLEscape)
		if err != nil {
			t.Errorf("%s: Annotate: %s", name, err)
			continue
		}

		expPath := path + ".html"
		if *saveExp {
			err = ioutil.WriteFile(expPath, got, 0700)
			if err != nil {
				t.Fatal(err)
			}
			continue
		}

		want, err := ioutil.ReadFile(expPath)
		if err != nil {
			t.Fatal(err)
		}

		want = bytes.TrimSpace(want)
		got = bytes.TrimSpace(got)

		if !bytes.Equal(want, got) {
			t.Errorf("%s: want %q, got %q", name, want, got)
			continue
		}
	}

	if *saveExp {
		t.Fatal("overwrote all expected output files with actual output (run tests again without -exp)")
	}
}

func makeFakeData(size1, size2 int) ([]byte, Annotations) {
	input := []byte(strings.Repeat(strings.Repeat("a", size1)+"⌘", size2))
	inputLength := utf8.RuneCount(input)
	n := len(input)/2 - (size1+1)/2
	anns := make(Annotations, n)
	for i := 0; i < n; i++ {
		if i%2 == 0 {
			anns[i] = &Annotation{Start: 2 * i, End: 2*i + 1}
		} else {
			anns[i] = &Annotation{Start: 2*i - 50, End: 2*i + 50}
			if anns[i].Start < 0 {
				anns[i].Start = 0
				anns[i].End = i
			}
			if anns[i].End >= inputLength {
				anns[i].End = inputLength
			}
		}
		anns[i].Left = []byte("L")  //[]byte(strings.Repeat("L", i%20))
		anns[i].Right = []byte("R") //[]byte(strings.Repeat("R", i%20))
		anns[i].WantInner = i % 5
	}
	sort.Sort(anns)
	return input, anns
}

func TestAnnotate_GeneratedData(t *testing.T) {
	input, anns := makeFakeData(1, 15)

	fail := func(err error) {
		annStrs := make([]string, len(anns))
		for i, a := range anns {
			annStrs[i] = fmt.Sprintf("%v", a)
		}
		t.Fatalf("Annotate: %s\n\nInput was:\n%q\n\nAnnotations:\n%s", err, input, strings.Join(annStrs, "\n"))
	}

	tm := time.NewTimer(time.Millisecond * 500)
	done := make(chan error)

	go func() {
		_, err := Annotate(input, anns, nil)
		done <- err
	}()

	select {
	case <-tm.C:
		fail(errors.New("timed out (is there an infinite loop?)"))
	case err := <-done:
		if err != nil {
			fail(err)
		}
	}
}

func BenchmarkAnnotate(b *testing.B) {
	input, anns := makeFakeData(99, 20)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_, err := Annotate(input, anns, nil)
		if err != nil {
			b.Fatal(err)
		}
	}
}
<|endoftext|>