<commit_before>/*
 * Copyright (C) 1999-2019 Alibaba Group Holding Limited
 */
package config

import (
	"bytes"
	"strings"
	"testing"

	"github.com/aliyun/alibaba-cloud-sdk-go/sdk"

	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/signers"
	"github.com/aliyun/aliyun-cli/cli"

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

func TestNewProfile(t *testing.T) {
	exp := Profile{
		Name:            "default",
		Mode:            AK,
		OutputFormat:    "json",
		Language:        "en",
		AccessKeyId:     "",
		AccessKeySecret: "",
		StsToken:        "",
		RamRoleName:     "",

		RamRoleArn:      "",
		RoleSessionName: "",
		PrivateKey:      "",
		KeyPairName:     "",
		ExpiredSeconds:  0,
		Verified:        "",
		RegionId:        "",
		Site:            "",
		RetryTimeout:    0,
		RetryCount:      0,
	}

	p := NewProfile("default")
	assert.Equal(t, exp, p)
}

func TestProfile(t *testing.T) {
	//ValidateAK
	p := NewProfile("default")
	assert.EqualError(t, p.ValidateAK(), "invalid access_key_id: ")
	p.AccessKeyId = "*****"
	assert.EqualError(t, p.ValidateAK(), "invaild access_key_secret: ")
	p.AccessKeySecret = "++++++"
	assert.Nil(t, p.ValidateAK())

	//Validate
	assert.EqualError(t, p.Validate(), "region can't be empty")
	p.RegionId = "*dflsj"
	assert.EqualError(t, p.Validate(), "invailed region *dflsj")
	p.RegionId = "cn-hangzhou"

	p.Mode = ""
	assert.EqualError(t, p.Validate(), "profile default is not configure yet, run `aliyun configure --profile default` first")

	p.Mode = AK
	assert.Nil(t, p.Validate())

	p.Mode = StsToken
	assert.EqualError(t, p.Validate(), "invailed sts_token")

	p.Mode = RamRoleArn
	assert.EqualError(t, p.Validate(), "invailed ram_role_arn")
	p.RamRoleArn = "RamRoleArn"
	assert.EqualError(t, p.Validate(), "invailed role_session_name")

	p.Mode = EcsRamRole
	//TODO maybe there is a problem

	p.Mode = RsaKeyPair
	assert.EqualError(t, p.Validate(), "invailed private_key")
	p.PrivateKey = "******"
	assert.EqualError(t, p.Validate(), "invailed key_pair_name")

	p.Mode = "free"
	assert.EqualError(t, p.Validate(), "invailed mode: free")

	//GetParent
	assert.Nil(t, p.GetParent())

	//OverwriteWithFlags
	w := new(bytes.Buffer)
	ctx := cli.NewCommandContext(w)
	AddFlags(ctx.Flags())

	p.AccessKeyId = ""
	p.AccessKeySecret = ""
	p.StsToken = ""
	p.RegionId = ""
	p.OverwriteWithFlags(ctx)
	assert.Equal(t, Profile{Name: "default", Mode: "free", RamRoleArn: "RamRoleArn", PrivateKey: "******", OutputFormat: "json", RetryCount: 0, RetryTimeout: 0, Language: "en"}, p)

	p.AccessKeyId = "****"
	p.AccessKeySecret = "++++"
	p.StsToken = "----"
	p.OverwriteWithFlags(ctx)
	assert.Equal(t, Profile{Name: "default", Mode: StsToken, StsToken: "----", AccessKeyId: "****", AccessKeySecret: "++++", RamRoleArn: "RamRoleArn", PrivateKey: "******", OutputFormat: "json", RetryCount: 0, RetryTimeout: 0, Language: "en"}, p)

	p.StsToken = ""
	p.RamRoleArn = "----"
	p.OverwriteWithFlags(ctx)
	assert.Equal(t, Profile{Name: "default", Mode: RamRoleArn, RamRoleArn: "----", AccessKeyId: "****", AccessKeySecret: "++++", PrivateKey: "******", OutputFormat: "json", RetryCount: 0, RetryTimeout: 0, Language: "en"}, p)

	p.AccessKeyId = ""
	p.AccessKeySecret = ""
	p.PrivateKey = "****"
	p.KeyPairName = "++++"
	p.OverwriteWithFlags(ctx)
	assert.Equal(t, Profile{Name: "default", Mode: RsaKeyPair, KeyPairName: "++++", RamRoleArn: "----", PrivateKey: "****", OutputFormat: "json", RetryCount: 0, RetryTimeout: 0, Language: "en"}, p)

	p.PrivateKey = ""
	p.KeyPairName = ""
	p.RamRoleName = "RamRoleName"
	p.OverwriteWithFlags(ctx)
	assert.Equal(t, Profile{Name: "default", Mode: EcsRamRole, RamRoleArn: "----", RamRoleName: "RamRoleName", OutputFormat: "json", RetryCount: 0, RetryTimeout: 0, Language: "en"}, p)

	//GetClient
	p.RetryTimeout = 1
	p.RetryCount = 1
	p.Mode = "free"
	sdkClient, err := p.GetClient(ctx)
	assert.Nil(t, sdkClient)
	assert.EqualError(t, err, "unexcepted certificate mode: free")

	p.Mode = AK
	sdkClient, err = p.GetClient(ctx)
	assert.Nil(t, sdkClient)
	assert.NotNil(t, err)

	p.Mode = StsToken
	sdkClient, err = p.GetClient(ctx)
	assert.Nil(t, err)
	assert.NotNil(t, sdkClient)

	p.Mode = RamRoleArn
	sdkClient, err = p.GetClient(ctx)
	assert.Nil(t, sdkClient)
	assert.NotNil(t, err)

	p.Mode = EcsRamRole
	sdkClient, err = p.GetClient(ctx)
	assert.Nil(t, sdkClient)
	assert.NotNil(t, err)

	p.Mode = RsaKeyPair
	sdkClient, err = p.GetClient(ctx)
	assert.Nil(t, err)
	assert.NotNil(t, sdkClient)

	//GetSessionCredential
	p.Mode = AK
	sessionCredential, err := p.GetSessionCredential()
	assert.Nil(t, err)
	assert.Equal(t, &signers.SessionCredential{AccessKeyId: p.AccessKeyId, AccessKeySecret: p.AccessKeySecret}, sessionCredential)

	p.Mode = StsToken
	sessionCredential, err = p.GetSessionCredential()
	assert.Nil(t, err)
	assert.Equal(t, &signers.SessionCredential{AccessKeyId: p.AccessKeyId, AccessKeySecret: p.AccessKeySecret, StsToken: p.StsToken}, sessionCredential)

	p.Mode = RamRoleArn
	sessionCredential, err = p.GetSessionCredential()
	assert.NotNil(t, err)
	assert.Nil(t, sessionCredential)

	p.Mode = EcsRamRole
	sessionCredential, err = p.GetSessionCredential()
	assert.NotNil(t, err)
	assert.Nil(t, sessionCredential)

	p.Mode = "free"
	sessionCredential, err = p.GetSessionCredential()
	assert.EqualError(t, err, "unsupported mode 'free' to GetSessionCredential")
	assert.Nil(t, sessionCredential)

	//GetClientByAK
	sdkCF := &sdk.Config{}
	sdkClient, err = p.GetClientByAK(sdkCF)
	assert.Nil(t, sdkClient)
	assert.EqualError(t, err, "AccessKeyId/AccessKeySecret is empty! run `aliyun configure` first")

	p.AccessKeyId = "AccessKeyId"
	p.AccessKeySecret = "AccessKeySecret"
	p.RegionId = ""
	sdkClient, err = p.GetClientByAK(sdkCF)
	assert.Nil(t, sdkClient)
	assert.EqualError(t, err, "default RegionId is empty! run `aliyun configure` first")

	p.RegionId = "cn-hangzhou"
	sdkClient, err = p.GetClientByAK(sdkCF)
	assert.Nil(t, err)
	assert.NotNil(t, sdkClient)

	//GetClientBySts
	p.StsToken = "StsToken"
	sdkClient, err = p.GetClientBySts(sdkCF)
	assert.Nil(t, err)
	assert.NotNil(t, sdkClient)

	//GetSessionCredentialByRoleArn
	p.AccessKeyId = ""
	p.AccessKeySecret = ""
	sessionCredential, err = p.GetSessionCredentialByRoleArn()
	assert.Nil(t, sessionCredential)
	assert.True(t, strings.HasPrefix(err.Error(), "sts:AssumeRole() failed"))

	//GetClientByRoleArn
	// p.GetClientByRoleArn(sdkCF)

	//GetClientByPrivateKey
	sdkClient, err = p.GetClientByPrivateKey(sdkCF)
	assert.Nil(t, err)
	assert.NotNil(t, sdkClient)

}

func TestIsRegion(t *testing.T) {
	assert.False(t, IsRegion("#$adf"))
	assert.True(t, IsRegion("2kf"))
}
<commit_msg>update Profile_test to pass through CI<commit_after>/*
 * Copyright (C) 1999-2019 Alibaba Group Holding Limited
 */
package config

import (
	"bytes"
	"os"
	"strings"
	"testing"

	"github.com/aliyun/alibaba-cloud-sdk-go/sdk"

	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/signers"
	"github.com/aliyun/aliyun-cli/cli"

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

func TestNewProfile(t *testing.T) {
	exp := Profile{
		Name:            "default",
		Mode:            AK,
		OutputFormat:    "json",
		Language:        "en",
		AccessKeyId:     "",
		AccessKeySecret: "",
		StsToken:        "",
		RamRoleName:     "",

		RamRoleArn:      "",
		RoleSessionName: "",
		PrivateKey:      "",
		KeyPairName:     "",
		ExpiredSeconds:  0,
		Verified:        "",
		RegionId:        "",
		Site:            "",
		RetryTimeout:    0,
		RetryCount:      0,
	}

	p := NewProfile("default")
	assert.Equal(t, exp, p)
}

func TestProfile(t *testing.T) {
	ACCESS_KEY_ID_env := os.Getenv("ACCESS_KEY_ID")
	if ACCESS_KEY_ID_env != "" {
		os.Setenv("ACCESS_KEY_ID", "")
		defer func() {
			os.Setenv("ACCESS_KEY_ID", ACCESS_KEY_ID_env)
		}()
	}
	ACCESS_KEY_SECRET_env := os.Getenv("ACCESS_KEY_SECRET")
	if ACCESS_KEY_ID_env != "" {
		os.Setenv("ACCESS_KEY_SECRET", "")
		defer func() {
			os.Setenv("ACCESS_KEY_SECRET", ACCESS_KEY_SECRET_env)
		}()
	}

	//ValidateAK
	p := NewProfile("default")
	assert.EqualError(t, p.ValidateAK(), "invalid access_key_id: ")
	p.AccessKeyId = "*****"
	assert.EqualError(t, p.ValidateAK(), "invaild access_key_secret: ")
	p.AccessKeySecret = "++++++"
	assert.Nil(t, p.ValidateAK())

	//Validate
	assert.EqualError(t, p.Validate(), "region can't be empty")
	p.RegionId = "*dflsj"
	assert.EqualError(t, p.Validate(), "invailed region *dflsj")
	p.RegionId = "cn-hangzhou"

	p.Mode = ""
	assert.EqualError(t, p.Validate(), "profile default is not configure yet, run `aliyun configure --profile default` first")

	p.Mode = AK
	assert.Nil(t, p.Validate())

	p.Mode = StsToken
	assert.EqualError(t, p.Validate(), "invailed sts_token")

	p.Mode = RamRoleArn
	assert.EqualError(t, p.Validate(), "invailed ram_role_arn")
	p.RamRoleArn = "RamRoleArn"
	assert.EqualError(t, p.Validate(), "invailed role_session_name")

	p.Mode = EcsRamRole
	//TODO maybe there is a problem

	p.Mode = RsaKeyPair
	assert.EqualError(t, p.Validate(), "invailed private_key")
	p.PrivateKey = "******"
	assert.EqualError(t, p.Validate(), "invailed key_pair_name")

	p.Mode = "free"
	assert.EqualError(t, p.Validate(), "invailed mode: free")

	//GetParent
	assert.Nil(t, p.GetParent())

	//OverwriteWithFlags
	w := new(bytes.Buffer)
	ctx := cli.NewCommandContext(w)
	AddFlags(ctx.Flags())

	p.AccessKeyId = ""
	p.AccessKeySecret = ""
	p.StsToken = ""
	p.RegionId = ""
	p.OverwriteWithFlags(ctx)
	assert.Equal(t, Profile{Name: "default", Mode: "free", RamRoleArn: "RamRoleArn", PrivateKey: "******", OutputFormat: "json", RetryCount: 0, RetryTimeout: 0, Language: "en"}, p)

	p.AccessKeyId = "****"
	p.AccessKeySecret = "++++"
	p.StsToken = "----"
	p.OverwriteWithFlags(ctx)
	assert.Equal(t, Profile{Name: "default", Mode: StsToken, StsToken: "----", AccessKeyId: "****", AccessKeySecret: "++++", RamRoleArn: "RamRoleArn", PrivateKey: "******", OutputFormat: "json", RetryCount: 0, RetryTimeout: 0, Language: "en"}, p)

	p.StsToken = ""
	p.RamRoleArn = "----"
	p.OverwriteWithFlags(ctx)
	assert.Equal(t, Profile{Name: "default", Mode: RamRoleArn, RamRoleArn: "----", AccessKeyId: "****", AccessKeySecret: "++++", PrivateKey: "******", OutputFormat: "json", RetryCount: 0, RetryTimeout: 0, Language: "en"}, p)

	p.AccessKeyId = ""
	p.AccessKeySecret = ""
	p.PrivateKey = "****"
	p.KeyPairName = "++++"
	p.OverwriteWithFlags(ctx)
	assert.Equal(t, Profile{Name: "default", Mode: RsaKeyPair, KeyPairName: "++++", RamRoleArn: "----", PrivateKey: "****", OutputFormat: "json", RetryCount: 0, RetryTimeout: 0, Language: "en"}, p)

	p.PrivateKey = ""
	p.KeyPairName = ""
	p.RamRoleName = "RamRoleName"
	p.OverwriteWithFlags(ctx)
	assert.Equal(t, Profile{Name: "default", Mode: EcsRamRole, RamRoleArn: "----", RamRoleName: "RamRoleName", OutputFormat: "json", RetryCount: 0, RetryTimeout: 0, Language: "en"}, p)

	//GetClient
	p.RetryTimeout = 1
	p.RetryCount = 1
	p.Mode = "free"
	sdkClient, err := p.GetClient(ctx)
	assert.Nil(t, sdkClient)
	assert.EqualError(t, err, "unexcepted certificate mode: free")

	p.Mode = AK
	sdkClient, err = p.GetClient(ctx)
	assert.Nil(t, sdkClient)
	assert.NotNil(t, err)

	p.Mode = StsToken
	sdkClient, err = p.GetClient(ctx)
	assert.Nil(t, err)
	assert.NotNil(t, sdkClient)

	p.Mode = RamRoleArn
	sdkClient, err = p.GetClient(ctx)
	assert.Nil(t, sdkClient)
	assert.NotNil(t, err)

	p.Mode = EcsRamRole
	sdkClient, err = p.GetClient(ctx)
	assert.Nil(t, sdkClient)
	assert.NotNil(t, err)

	p.Mode = RsaKeyPair
	sdkClient, err = p.GetClient(ctx)
	assert.Nil(t, err)
	assert.NotNil(t, sdkClient)

	//GetSessionCredential
	p.Mode = AK
	sessionCredential, err := p.GetSessionCredential()
	assert.Nil(t, err)
	assert.Equal(t, &signers.SessionCredential{AccessKeyId: p.AccessKeyId, AccessKeySecret: p.AccessKeySecret}, sessionCredential)

	p.Mode = StsToken
	sessionCredential, err = p.GetSessionCredential()
	assert.Nil(t, err)
	assert.Equal(t, &signers.SessionCredential{AccessKeyId: p.AccessKeyId, AccessKeySecret: p.AccessKeySecret, StsToken: p.StsToken}, sessionCredential)

	p.Mode = RamRoleArn
	sessionCredential, err = p.GetSessionCredential()
	assert.NotNil(t, err)
	assert.Nil(t, sessionCredential)

	p.Mode = EcsRamRole
	sessionCredential, err = p.GetSessionCredential()
	assert.NotNil(t, err)
	assert.Nil(t, sessionCredential)

	p.Mode = "free"
	sessionCredential, err = p.GetSessionCredential()
	assert.EqualError(t, err, "unsupported mode 'free' to GetSessionCredential")
	assert.Nil(t, sessionCredential)

	//GetClientByAK
	sdkCF := &sdk.Config{}
	sdkClient, err = p.GetClientByAK(sdkCF)
	assert.Nil(t, sdkClient)
	assert.EqualError(t, err, "AccessKeyId/AccessKeySecret is empty! run `aliyun configure` first")

	p.AccessKeyId = "AccessKeyId"
	p.AccessKeySecret = "AccessKeySecret"
	p.RegionId = ""
	sdkClient, err = p.GetClientByAK(sdkCF)
	assert.Nil(t, sdkClient)
	assert.EqualError(t, err, "default RegionId is empty! run `aliyun configure` first")

	p.RegionId = "cn-hangzhou"
	sdkClient, err = p.GetClientByAK(sdkCF)
	assert.Nil(t, err)
	assert.NotNil(t, sdkClient)

	//GetClientBySts
	p.StsToken = "StsToken"
	sdkClient, err = p.GetClientBySts(sdkCF)
	assert.Nil(t, err)
	assert.NotNil(t, sdkClient)

	//GetSessionCredentialByRoleArn
	p.AccessKeyId = ""
	p.AccessKeySecret = ""
	sessionCredential, err = p.GetSessionCredentialByRoleArn()
	assert.Nil(t, sessionCredential)
	assert.True(t, strings.HasPrefix(err.Error(), "sts:AssumeRole() failed"))

	//GetClientByRoleArn
	// p.GetClientByRoleArn(sdkCF)

	//GetClientByPrivateKey
	sdkClient, err = p.GetClientByPrivateKey(sdkCF)
	assert.Nil(t, err)
	assert.NotNil(t, sdkClient)

}

func TestIsRegion(t *testing.T) {
	assert.False(t, IsRegion("#$adf"))
	assert.True(t, IsRegion("2kf"))
}
<|endoftext|>


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

// Package container contains a Google Container Engine client.
//
// For more information about the API,
// see https://cloud.google.com/container-engine/docs
package container // import "cloud.google.com/go/container"

import (
	"errors"
	"fmt"
	"time"

	"golang.org/x/net/context"
	raw "google.golang.org/api/container/v1"
	"google.golang.org/api/option"
	"google.golang.org/api/transport"
)

type Type string

const (
	TypeCreate = Type("createCluster")
	TypeDelete = Type("deleteCluster")
)

type Status string

const (
	Done         = Status("done")
	Pending      = Status("pending")
	Running      = Status("running")
	Error        = Status("error")
	Provisioning = Status("provisioning")
	Stopping     = Status("stopping")
)

const prodAddr = "https://container.googleapis.com/"
const userAgent = "gcloud-golang-container/20151008"

// Client is a Google Container Engine client, which may be used to manage
// clusters with a project.  It must be constructed via NewClient.
type Client struct {
	projectID string
	svc       *raw.Service
}

// NewClient creates a new Google Container Engine client.
func NewClient(ctx context.Context, projectID string, opts ...option.ClientOption) (*Client, error) {
	o := []option.ClientOption{
		option.WithEndpoint(prodAddr),
		option.WithScopes(raw.CloudPlatformScope),
		option.WithUserAgent(userAgent),
	}
	o = append(o, opts...)
	httpClient, endpoint, err := transport.NewHTTPClient(ctx, o...)
	if err != nil {
		return nil, fmt.Errorf("dialing: %v", err)
	}

	svc, err := raw.New(httpClient)
	if err != nil {
		return nil, fmt.Errorf("constructing container client: %v", err)
	}
	svc.BasePath = endpoint

	c := &Client{
		projectID: projectID,
		svc:       svc,
	}

	return c, nil
}

// Resource is a Google Container Engine cluster resource.
type Resource struct {
	// Name is the name of this cluster. The name must be unique
	// within this project and zone, and can be up to 40 characters.
	Name string

	// Description is the description of the cluster. Optional.
	Description string

	// Zone is the Google Compute Engine zone in which the cluster resides.
	Zone string

	// Status is the current status of the cluster. It could either be
	// StatusError, StatusProvisioning, StatusRunning or StatusStopping.
	Status Status

	// Num is the number of the nodes in this cluster resource.
	Num int64

	// APIVersion is the version of the Kubernetes master and kubelets running
	// in this cluster. Allowed value is 0.4.2, or leave blank to
	// pick up the latest stable release.
	APIVersion string

	// Endpoint is the IP address of this cluster's Kubernetes master.
	// The endpoint can be accessed at https://username:password@endpoint/.
	// See Username and Password fields for the username and password information.
	Endpoint string

	// Username is the username to use when accessing the Kubernetes master endpoint.
	Username string

	// Password is the password to use when accessing the Kubernetes master endpoint.
	Password string

	// ContainerIPv4CIDR is the IP addresses of the container pods in
	// this cluster, in CIDR notation (e.g. 1.2.3.4/29).
	ContainerIPv4CIDR string

	// ServicesIPv4CIDR is the IP addresses of the Kubernetes services in this
	// cluster, in CIDR notation (e.g. 1.2.3.4/29). Service addresses are
	// always in the 10.0.0.0/16 range.
	ServicesIPv4CIDR string

	// MachineType is a Google Compute Engine machine type (e.g. n1-standard-1).
	// If none set, the default type is used while creating a new cluster.
	MachineType string

	// This field is ignored. It was removed from the underlying container API in v1.
	SourceImage string

	// Created is the creation time of this cluster.
	Created time.Time
}

func resourceFromRaw(c *raw.Cluster) *Resource {
	if c == nil {
		return nil
	}
	r := &Resource{
		Name:              c.Name,
		Description:       c.Description,
		Zone:              c.Zone,
		Status:            Status(c.Status),
		Num:               c.InitialNodeCount,
		APIVersion:        c.InitialClusterVersion,
		Endpoint:          c.Endpoint,
		Username:          c.MasterAuth.Username,
		Password:          c.MasterAuth.Password,
		ContainerIPv4CIDR: c.ClusterIpv4Cidr,
		ServicesIPv4CIDR:  c.ServicesIpv4Cidr,
		MachineType:       c.NodeConfig.MachineType,
	}
	r.Created, _ = time.Parse(time.RFC3339, c.CreateTime)
	return r
}

func resourcesFromRaw(c []*raw.Cluster) []*Resource {
	r := make([]*Resource, len(c))
	for i, val := range c {
		r[i] = resourceFromRaw(val)
	}
	return r
}

// Op represents a Google Container Engine API operation.
type Op struct {
	// Name is the name of the operation.
	Name string

	// Zone is the Google Compute Engine zone.
	Zone string

	// This field is ignored. It was removed from the underlying container API in v1.
	TargetURL string

	// Type is the operation type. It could be either be TypeCreate or TypeDelete.
	Type Type

	// Status is the current status of this operation. It could be either
	// OpDone or OpPending.
	Status Status
}

func opFromRaw(o *raw.Operation) *Op {
	if o == nil {
		return nil
	}
	return &Op{
		Name:   o.Name,
		Zone:   o.Zone,
		Type:   Type(o.OperationType),
		Status: Status(o.Status),
	}
}

func opsFromRaw(o []*raw.Operation) []*Op {
	ops := make([]*Op, len(o))
	for i, val := range o {
		ops[i] = opFromRaw(val)
	}
	return ops
}

// Clusters returns a list of cluster resources from the specified zone.
// If no zone is specified, it returns all clusters under the user project.
func (c *Client) Clusters(ctx context.Context, zone string) ([]*Resource, error) {
	if zone == "" {
		resp, err := c.svc.Projects.Zones.Clusters.List(c.projectID, "-").Do()
		if err != nil {
			return nil, err
		}
		return resourcesFromRaw(resp.Clusters), nil
	}
	resp, err := c.svc.Projects.Zones.Clusters.List(c.projectID, zone).Do()
	if err != nil {
		return nil, err
	}
	return resourcesFromRaw(resp.Clusters), nil
}

// Cluster returns metadata about the specified cluster.
func (c *Client) Cluster(ctx context.Context, zone, name string) (*Resource, error) {
	resp, err := c.svc.Projects.Zones.Clusters.Get(c.projectID, zone, name).Do()
	if err != nil {
		return nil, err
	}
	return resourceFromRaw(resp), nil
}

// CreateCluster creates a new cluster with the provided metadata
// in the specified zone.
func (c *Client) CreateCluster(ctx context.Context, zone string, resource *Resource) (*Resource, error) {
	panic("not implemented")
}

// DeleteCluster deletes a cluster.
func (c *Client) DeleteCluster(ctx context.Context, zone, name string) error {
	_, err := c.svc.Projects.Zones.Clusters.Delete(c.projectID, zone, name).Do()
	return err
}

// Operations returns a list of operations from the specified zone.
// If no zone is specified, it looks up for all of the operations
// that are running under the user's project.
func (c *Client) Operations(ctx context.Context, zone string) ([]*Op, error) {
	if zone == "" {
		resp, err := c.svc.Projects.Zones.Operations.List(c.projectID, "-").Do()
		if err != nil {
			return nil, err
		}
		return opsFromRaw(resp.Operations), nil
	}
	resp, err := c.svc.Projects.Zones.Operations.List(c.projectID, zone).Do()
	if err != nil {
		return nil, err
	}
	return opsFromRaw(resp.Operations), nil
}

// Operation returns an operation.
func (c *Client) Operation(ctx context.Context, zone, name string) (*Op, error) {
	resp, err := c.svc.Projects.Zones.Operations.Get(c.projectID, zone, name).Do()
	if err != nil {
		return nil, err
	}
	if resp.StatusMessage != "" {
		return nil, errors.New(resp.StatusMessage)
	}
	return opFromRaw(resp), nil
}
<commit_msg>container: prefix statuses<commit_after>// Copyright 2014 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package container contains a Google Container Engine client.
//
// For more information about the API,
// see https://cloud.google.com/container-engine/docs
package container // import "cloud.google.com/go/container"

import (
	"errors"
	"fmt"
	"time"

	"golang.org/x/net/context"
	raw "google.golang.org/api/container/v1"
	"google.golang.org/api/option"
	"google.golang.org/api/transport"
)

type Type string

const (
	TypeCreate = Type("createCluster")
	TypeDelete = Type("deleteCluster")
)

type Status string

const (
	StatusDone         = Status("done")
	StatusPending      = Status("pending")
	StatusRunning      = Status("running")
	StatusError        = Status("error")
	StatusProvisioning = Status("provisioning")
	StatusStopping     = Status("stopping")
)

const prodAddr = "https://container.googleapis.com/"
const userAgent = "gcloud-golang-container/20151008"

// Client is a Google Container Engine client, which may be used to manage
// clusters with a project.  It must be constructed via NewClient.
type Client struct {
	projectID string
	svc       *raw.Service
}

// NewClient creates a new Google Container Engine client.
func NewClient(ctx context.Context, projectID string, opts ...option.ClientOption) (*Client, error) {
	o := []option.ClientOption{
		option.WithEndpoint(prodAddr),
		option.WithScopes(raw.CloudPlatformScope),
		option.WithUserAgent(userAgent),
	}
	o = append(o, opts...)
	httpClient, endpoint, err := transport.NewHTTPClient(ctx, o...)
	if err != nil {
		return nil, fmt.Errorf("dialing: %v", err)
	}

	svc, err := raw.New(httpClient)
	if err != nil {
		return nil, fmt.Errorf("constructing container client: %v", err)
	}
	svc.BasePath = endpoint

	c := &Client{
		projectID: projectID,
		svc:       svc,
	}

	return c, nil
}

// Resource is a Google Container Engine cluster resource.
type Resource struct {
	// Name is the name of this cluster. The name must be unique
	// within this project and zone, and can be up to 40 characters.
	Name string

	// Description is the description of the cluster. Optional.
	Description string

	// Zone is the Google Compute Engine zone in which the cluster resides.
	Zone string

	// Status is the current status of the cluster. It could either be
	// StatusError, StatusProvisioning, StatusRunning or StatusStopping.
	Status Status

	// Num is the number of the nodes in this cluster resource.
	Num int64

	// APIVersion is the version of the Kubernetes master and kubelets running
	// in this cluster. Allowed value is 0.4.2, or leave blank to
	// pick up the latest stable release.
	APIVersion string

	// Endpoint is the IP address of this cluster's Kubernetes master.
	// The endpoint can be accessed at https://username:password@endpoint/.
	// See Username and Password fields for the username and password information.
	Endpoint string

	// Username is the username to use when accessing the Kubernetes master endpoint.
	Username string

	// Password is the password to use when accessing the Kubernetes master endpoint.
	Password string

	// ContainerIPv4CIDR is the IP addresses of the container pods in
	// this cluster, in CIDR notation (e.g. 1.2.3.4/29).
	ContainerIPv4CIDR string

	// ServicesIPv4CIDR is the IP addresses of the Kubernetes services in this
	// cluster, in CIDR notation (e.g. 1.2.3.4/29). Service addresses are
	// always in the 10.0.0.0/16 range.
	ServicesIPv4CIDR string

	// MachineType is a Google Compute Engine machine type (e.g. n1-standard-1).
	// If none set, the default type is used while creating a new cluster.
	MachineType string

	// This field is ignored. It was removed from the underlying container API in v1.
	SourceImage string

	// Created is the creation time of this cluster.
	Created time.Time
}

func resourceFromRaw(c *raw.Cluster) *Resource {
	if c == nil {
		return nil
	}
	r := &Resource{
		Name:              c.Name,
		Description:       c.Description,
		Zone:              c.Zone,
		Status:            Status(c.Status),
		Num:               c.InitialNodeCount,
		APIVersion:        c.InitialClusterVersion,
		Endpoint:          c.Endpoint,
		Username:          c.MasterAuth.Username,
		Password:          c.MasterAuth.Password,
		ContainerIPv4CIDR: c.ClusterIpv4Cidr,
		ServicesIPv4CIDR:  c.ServicesIpv4Cidr,
		MachineType:       c.NodeConfig.MachineType,
	}
	r.Created, _ = time.Parse(time.RFC3339, c.CreateTime)
	return r
}

func resourcesFromRaw(c []*raw.Cluster) []*Resource {
	r := make([]*Resource, len(c))
	for i, val := range c {
		r[i] = resourceFromRaw(val)
	}
	return r
}

// Op represents a Google Container Engine API operation.
type Op struct {
	// Name is the name of the operation.
	Name string

	// Zone is the Google Compute Engine zone.
	Zone string

	// This field is ignored. It was removed from the underlying container API in v1.
	TargetURL string

	// Type is the operation type. It could be either be TypeCreate or TypeDelete.
	Type Type

	// Status is the current status of this operation. It could be either
	// OpDone or OpPending.
	Status Status
}

func opFromRaw(o *raw.Operation) *Op {
	if o == nil {
		return nil
	}
	return &Op{
		Name:   o.Name,
		Zone:   o.Zone,
		Type:   Type(o.OperationType),
		Status: Status(o.Status),
	}
}

func opsFromRaw(o []*raw.Operation) []*Op {
	ops := make([]*Op, len(o))
	for i, val := range o {
		ops[i] = opFromRaw(val)
	}
	return ops
}

// Clusters returns a list of cluster resources from the specified zone.
// If no zone is specified, it returns all clusters under the user project.
func (c *Client) Clusters(ctx context.Context, zone string) ([]*Resource, error) {
	if zone == "" {
		resp, err := c.svc.Projects.Zones.Clusters.List(c.projectID, "-").Do()
		if err != nil {
			return nil, err
		}
		return resourcesFromRaw(resp.Clusters), nil
	}
	resp, err := c.svc.Projects.Zones.Clusters.List(c.projectID, zone).Do()
	if err != nil {
		return nil, err
	}
	return resourcesFromRaw(resp.Clusters), nil
}

// Cluster returns metadata about the specified cluster.
func (c *Client) Cluster(ctx context.Context, zone, name string) (*Resource, error) {
	resp, err := c.svc.Projects.Zones.Clusters.Get(c.projectID, zone, name).Do()
	if err != nil {
		return nil, err
	}
	return resourceFromRaw(resp), nil
}

// CreateCluster creates a new cluster with the provided metadata
// in the specified zone.
func (c *Client) CreateCluster(ctx context.Context, zone string, resource *Resource) (*Resource, error) {
	panic("not implemented")
}

// DeleteCluster deletes a cluster.
func (c *Client) DeleteCluster(ctx context.Context, zone, name string) error {
	_, err := c.svc.Projects.Zones.Clusters.Delete(c.projectID, zone, name).Do()
	return err
}

// Operations returns a list of operations from the specified zone.
// If no zone is specified, it looks up for all of the operations
// that are running under the user's project.
func (c *Client) Operations(ctx context.Context, zone string) ([]*Op, error) {
	if zone == "" {
		resp, err := c.svc.Projects.Zones.Operations.List(c.projectID, "-").Do()
		if err != nil {
			return nil, err
		}
		return opsFromRaw(resp.Operations), nil
	}
	resp, err := c.svc.Projects.Zones.Operations.List(c.projectID, zone).Do()
	if err != nil {
		return nil, err
	}
	return opsFromRaw(resp.Operations), nil
}

// Operation returns an operation.
func (c *Client) Operation(ctx context.Context, zone, name string) (*Op, error) {
	resp, err := c.svc.Projects.Zones.Operations.Get(c.projectID, zone, name).Do()
	if err != nil {
		return nil, err
	}
	if resp.StatusMessage != "" {
		return nil, errors.New(resp.StatusMessage)
	}
	return opFromRaw(resp), nil
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"os/exec"
	"testing"

	"net/http"

	"github.com/spring1843/chat-server/src/config"
	"github.com/spring1843/chat-server/src/shared/logs"
)

func TestCanStartWebWithHTTP(t *testing.T) {
	config := config.FromFile("./config.json")
	config.WebAddress += "1"
	srv := getTLSServer(getMultiplexer(), config.WebAddress)
	go func() {
		t.Logf("Starting http on %s", config.WebAddress)
		if err := srv.ListenAndServe(); err != nil {
			logs.FatalIfErrf(err, "Couldn't start http on %s", config.WebAddress)
		}
	}()

	resp, err := http.Get("http://" + config.WebAddress + "/api/status")
	if err != nil {
		t.Fatalf("couldn't get api status endpoint after serving http. Error %s", err)
	}

	if resp.StatusCode != http.StatusOK {
		t.Fatalf("Expected status %d, got %d", http.StatusOK, resp.StatusCode)
	}
}

func TestCanStartWebWithHTTPS(t *testing.T) {
	config := config.FromFile("./config.json")
	config.WebAddress += "2"
	srv := getTLSServer(getMultiplexer(), config.WebAddress)
	go func() {
		t.Logf("Starting https on %s", config.WebAddress)
		if err := srv.ListenAndServeTLS("tls.crt", "tls.key"); err != nil {
			logs.FatalIfErrf(err, "Couldn't start https on %s", config.WebAddress)
		}
	}()

	resp, err := http.Get("https://" + config.WebAddress + "/api/status")
	if err != nil {
		t.Fatalf("couldn't get api status endpoint after serving https. Error %s", err)
	}

	if resp.StatusCode != http.StatusOK {
		t.Fatalf("Expected status %d, got %d", http.StatusOK, resp.StatusCode)
	}
}

func TestEmptyDrivers(t *testing.T) {
	config := new(config.Config)
	bootstrap(*config)
	if chatServer == nil {
		t.Fatalf("Empty web and telnet addresses did not start the server.")
	}
}

func TestErrorOnInvalidTelnet(t *testing.T) {
	config := new(config.Config)
	config.TelnetAddress = "-1"
	if err := startTelnet(*config); err == nil {
		t.Fatalf("Expected error on invalid telnet address")
	}
}

// TestCanRunDefaultConfig run bootstrap and expects it to be able to run with config.json values
func TestCanRunDefaultConfig(t *testing.T) {
	if os.Getenv("BE_CRASHER") == "1" {
		config := config.FromFile("./config.json")
		bootstrap(config)
		return
	}
	cmd := exec.Command(os.Args[0], "-test.run=TestCanRunDefaultConfig")
	cmd.Env = append(os.Environ(), "BE_CRASHER=1")
	err := cmd.Run()
	if e, ok := err.(*exec.ExitError); ok && !e.Success() {
		return
	}
	if err != nil {
		t.Fatalf("Couldnt run with config.json values, Test exited with status 1, expected 1. Error %s", err)
	}
}

// TestCanCrashOnBadConfig run bootstrap and expects it to exit with status 1 (fatal error) when config values are not valid
func TestCanCrashOnBadConfig(t *testing.T) {
	if os.Getenv("BE_CRASHER") == "1" {
		config := config.FromFile("./config.json")

		// Make config invalid
		config.TelnetAddress = "-1"

		bootstrap(config)
		return
	}
	cmd := exec.Command(os.Args[0], "-test.run=TestCanCrashOnBadConfig")
	cmd.Env = append(os.Environ(), "BE_CRASHER=1")
	err := cmd.Run()
	if e, ok := err.(*exec.ExitError); ok && !e.Success() {
		return
	}
	t.Fatalf("Did not fail run with invalid config.json values, Test exited with status 0, expected 1")
}
<commit_msg>Reuse startWeb<commit_after>package main

import (
	"os"
	"os/exec"
	"testing"

	"net/http"

	"github.com/spring1843/chat-server/src/config"
	"github.com/spring1843/chat-server/src/shared/logs"
)

func TestCanStartWebWithHTTP(t *testing.T) {
	config := config.FromFile("./config.json")
	config.WebAddress += "1"
	srv := getTLSServer(getMultiplexer(), config.WebAddress)
	go func() {
		t.Logf("Starting http on %s", config.WebAddress)
		if err := srv.ListenAndServe(); err != nil {
			logs.FatalIfErrf(err, "Couldn't start http on %s", config.WebAddress)
		}
	}()

	resp, err := http.Get("http://" + config.WebAddress + "/api/status")
	if err != nil {
		t.Fatalf("couldn't get api status endpoint after serving http. Error %s", err)
	}

	if resp.StatusCode != http.StatusOK {
		t.Fatalf("Expected status %d, got %d", http.StatusOK, resp.StatusCode)
	}
}

func TestCanStartWebWithHTTPS(t *testing.T) {
	config := config.FromFile("./config.json")
	config.WebAddress += "2"
	startWeb(config)

	resp, err := http.Get("https://" + config.WebAddress + "/api/status")
	if err != nil {
		t.Fatalf("couldn't get api status endpoint after serving https. Error %s", err)
	}

	if resp.StatusCode != http.StatusOK {
		t.Fatalf("Expected status %d, got %d", http.StatusOK, resp.StatusCode)
	}
}

func TestEmptyDrivers(t *testing.T) {
	config := new(config.Config)
	bootstrap(*config)
	if chatServer == nil {
		t.Fatalf("Empty web and telnet addresses did not start the server.")
	}
}

func TestErrorOnInvalidTelnet(t *testing.T) {
	config := new(config.Config)
	config.TelnetAddress = "-1"
	if err := startTelnet(*config); err == nil {
		t.Fatalf("Expected error on invalid telnet address")
	}
}

// TestCanRunDefaultConfig run bootstrap and expects it to be able to run with config.json values
func TestCanRunDefaultConfig(t *testing.T) {
	if os.Getenv("BE_CRASHER") == "1" {
		config := config.FromFile("./config.json")
		bootstrap(config)
		return
	}
	cmd := exec.Command(os.Args[0], "-test.run=TestCanRunDefaultConfig")
	cmd.Env = append(os.Environ(), "BE_CRASHER=1")
	err := cmd.Run()
	if e, ok := err.(*exec.ExitError); ok && !e.Success() {
		return
	}
	if err != nil {
		t.Fatalf("Couldnt run with config.json values, Test exited with status 1, expected 1. Error %s", err)
	}
}

// TestCanCrashOnBadConfig run bootstrap and expects it to exit with status 1 (fatal error) when config values are not valid
func TestCanCrashOnBadConfig(t *testing.T) {
	if os.Getenv("BE_CRASHER") == "1" {
		config := config.FromFile("./config.json")

		// Make config invalid
		config.TelnetAddress = "-1"

		bootstrap(config)
		return
	}
	cmd := exec.Command(os.Args[0], "-test.run=TestCanCrashOnBadConfig")
	cmd.Env = append(os.Environ(), "BE_CRASHER=1")
	err := cmd.Run()
	if e, ok := err.(*exec.ExitError); ok && !e.Success() {
		return
	}
	t.Fatalf("Did not fail run with invalid config.json values, Test exited with status 0, expected 1")
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"regexp"
	"strings"
	"text/template"

	"github.com/github/hub/md2roff"
	"github.com/github/hub/utils"
	"github.com/russross/blackfriday"
)

var (
	flagManual,
	flagVersion,
	flagTemplate,
	flagDate string

	xRefRe = regexp.MustCompile(`\b(?P<name>[a-z][\w-]*)\((?P<section>\d)\)`)

	pageIndex map[string]bool
)

func init() {
	pageIndex = make(map[string]bool)
}

type templateData struct {
	Contents string
	Manual   string
	Date     string
	Version  string
	Title    string
	Name     string
	Section  uint8
}

func generateFromFile(mdFile string) error {
	content, err := ioutil.ReadFile(mdFile)
	if err != nil {
		return err
	}

	roffFile := strings.TrimSuffix(mdFile, ".md")
	roffBuf, err := os.OpenFile(roffFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
	if err != nil {
		return err
	}
	defer roffBuf.Close()

	htmlFile := strings.TrimSuffix(mdFile, ".md") + ".html"
	htmlBuf, err := os.OpenFile(htmlFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
	if err != nil {
		return err
	}
	defer htmlBuf.Close()

	html := blackfriday.NewHTMLRenderer(blackfriday.HTMLRendererParameters{
		Flags: blackfriday.HTMLFlagsNone,
	})
	roff := &md2roff.RoffRenderer{
		Version: flagVersion,
		Date:    flagDate,
	}

	htmlGenBuf := &bytes.Buffer{}
	var htmlWriteBuf io.Writer = htmlBuf
	if flagTemplate != "" {
		htmlWriteBuf = htmlGenBuf
	}

	md2roff.Generate(content,
		md2roff.Opt(roffBuf, roff),
		md2roff.Opt(htmlWriteBuf, html),
	)

	if flagTemplate != "" {
		htmlGenBytes, err := ioutil.ReadAll(htmlGenBuf)
		if err != nil {
			return err
		}
		content := ""
		if contentLines := strings.Split(string(htmlGenBytes), "\n"); len(contentLines) > 1 {
			content = strings.Join(contentLines[1:], "\n")
		}

		currentPage := fmt.Sprintf("%s(%d)", roff.Name, roff.Section)
		content = xRefRe.ReplaceAllStringFunc(content, func(match string) string {
			if match == currentPage {
				return match
			} else {
				matches := xRefRe.FindAllStringSubmatch(match, 1)
				fileName := fmt.Sprintf("%s.%s", matches[0][1], matches[0][2])
				if pageIndex[fileName] {
					return fmt.Sprintf(`<a href="./%s.html">%s</a>`, fileName, match)
				} else {
					return match
				}
			}
		})

		tmplData := templateData{
			Manual:   flagManual,
			Date:     flagDate,
			Contents: content,
			Title:    roff.Title,
			Section:  roff.Section,
			Name:     roff.Name,
			Version:  flagVersion,
		}

		templateFile, err := ioutil.ReadFile(flagTemplate)
		if err != nil {
			return err
		}
		tmpl, err := template.New("test").Parse(string(templateFile))
		if err != nil {
			return err
		}
		err = tmpl.Execute(htmlBuf, tmplData)
		if err != nil {
			return err
		}
	}

	return nil
}

func main() {
	p := utils.NewArgsParserWithUsage(`
		--manual NAME
		--version STR
		--template FILE
		--date DATE
	`)
	files, err := p.Parse(os.Args)
	if err != nil {
		panic(err)
	}
	flagManual = p.Value("--manual")
	flagVersion = p.Value("--version")
	flagTemplate = p.Value("--template")
	flagDate = p.Value("--date")

	for _, infile := range files {
		name := path.Base(infile)
		name = strings.TrimSuffix(name, ".md")
		pageIndex[name] = true
	}

	for _, infile := range files {
		err := generateFromFile(infile)
		if err != nil {
			panic(err)
		}
	}
}
<commit_msg>[md2roff] Provide more information around file errors<commit_after>package main

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"regexp"
	"strings"
	"text/template"

	"github.com/github/hub/md2roff"
	"github.com/github/hub/utils"
	"github.com/russross/blackfriday"
)

var (
	flagManual,
	flagVersion,
	flagTemplate,
	flagDate string

	xRefRe = regexp.MustCompile(`\b(?P<name>[a-z][\w-]*)\((?P<section>\d)\)`)

	pageIndex map[string]bool
)

func init() {
	pageIndex = make(map[string]bool)
}

type templateData struct {
	Contents string
	Manual   string
	Date     string
	Version  string
	Title    string
	Name     string
	Section  uint8
}

func generateFromFile(mdFile string) error {
	content, err := ioutil.ReadFile(mdFile)
	if err != nil {
		return fmt.Errorf("%s (%q)", err, mdFile)
	}

	roffFile := strings.TrimSuffix(mdFile, ".md")
	roffBuf, err := os.OpenFile(roffFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
	if err != nil {
		return fmt.Errorf("%s (%q)", err, roffFile)
	}
	defer roffBuf.Close()

	htmlFile := strings.TrimSuffix(mdFile, ".md") + ".html"
	htmlBuf, err := os.OpenFile(htmlFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
	if err != nil {
		return fmt.Errorf("%s (%q)", err, htmlFile)
	}
	defer htmlBuf.Close()

	html := blackfriday.NewHTMLRenderer(blackfriday.HTMLRendererParameters{
		Flags: blackfriday.HTMLFlagsNone,
	})
	roff := &md2roff.RoffRenderer{
		Version: flagVersion,
		Date:    flagDate,
	}

	htmlGenBuf := &bytes.Buffer{}
	var htmlWriteBuf io.Writer = htmlBuf
	if flagTemplate != "" {
		htmlWriteBuf = htmlGenBuf
	}

	md2roff.Generate(content,
		md2roff.Opt(roffBuf, roff),
		md2roff.Opt(htmlWriteBuf, html),
	)

	if flagTemplate != "" {
		htmlGenBytes, err := ioutil.ReadAll(htmlGenBuf)
		if err != nil {
			return fmt.Errorf("%s [%s]", err, "htmlGenBuf")
		}
		content := ""
		if contentLines := strings.Split(string(htmlGenBytes), "\n"); len(contentLines) > 1 {
			content = strings.Join(contentLines[1:], "\n")
		}

		currentPage := fmt.Sprintf("%s(%d)", roff.Name, roff.Section)
		content = xRefRe.ReplaceAllStringFunc(content, func(match string) string {
			if match == currentPage {
				return match
			} else {
				matches := xRefRe.FindAllStringSubmatch(match, 1)
				fileName := fmt.Sprintf("%s.%s", matches[0][1], matches[0][2])
				if pageIndex[fileName] {
					return fmt.Sprintf(`<a href="./%s.html">%s</a>`, fileName, match)
				} else {
					return match
				}
			}
		})

		tmplData := templateData{
			Manual:   flagManual,
			Date:     flagDate,
			Contents: content,
			Title:    roff.Title,
			Section:  roff.Section,
			Name:     roff.Name,
			Version:  flagVersion,
		}

		templateFile, err := ioutil.ReadFile(flagTemplate)
		if err != nil {
			return fmt.Errorf("%s (%q)", err, flagTemplate)
		}
		tmpl, err := template.New("test").Parse(string(templateFile))
		if err != nil {
			return err
		}
		err = tmpl.Execute(htmlBuf, tmplData)
		if err != nil {
			return err
		}
	}

	return nil
}

func main() {
	p := utils.NewArgsParserWithUsage(`
		--manual NAME
		--version STR
		--template FILE
		--date DATE
	`)
	files, err := p.Parse(os.Args)
	if err != nil {
		panic(err)
	}
	flagManual = p.Value("--manual")
	flagVersion = p.Value("--version")
	flagTemplate = p.Value("--template")
	flagDate = p.Value("--date")

	for _, infile := range files {
		name := path.Base(infile)
		name = strings.TrimSuffix(name, ".md")
		pageIndex[name] = true
	}

	for _, infile := range files {
		err := generateFromFile(infile)
		if err != nil {
			panic(err)
		}
	}
}
<|endoftext|>


<commit_before>package runtime_test

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

func checkGdbPython(t *testing.T) {
	cmd := exec.Command("gdb", "-nx", "-q", "--batch", "-ex", "python import sys; print('go gdb python support')")
	out, err := cmd.CombinedOutput()

	if err != nil {
		t.Skipf("skipping due to issue running gdb: %v", err)
	}
	if string(out) != "go gdb python support\n" {
		t.Skipf("skipping due to lack of python gdb support: %s", out)
	}
}

const helloSource = `
package main
import "fmt"
func main() {
	fmt.Println("hi")
}
`

func TestGdbLoadRuntimeSupport(t *testing.T) {
	checkGdbPython(t)

	dir, err := ioutil.TempDir("", "go-build")
	if err != nil {
		t.Fatalf("failed to create temp directory: %v", err)
	}
	defer os.RemoveAll(dir)

	src := filepath.Join(dir, "main.go")
	err = ioutil.WriteFile(src, []byte(helloSource), 0644)
	if err != nil {
		t.Fatalf("failed to create file: %v", err)
	}

	cmd := exec.Command("go", "build", "-o", "a.exe")
	cmd.Dir = dir
	out, err := cmd.CombinedOutput()
	if err != nil {
		t.Fatalf("building source %v\n%s", err, out)
	}

	got, _ := exec.Command("gdb", "-nx", "-q", "--batch", "-iex",
		fmt.Sprintf("add-auto-load-safe-path %s/src/runtime", runtime.GOROOT()),
		filepath.Join(dir, "a.exe")).CombinedOutput()
	if string(got) != "Loading Go Runtime support.\n" {
		t.Fatalf("%s", got)
	}
}
<commit_msg>runtime: skip the gdb test if -iex is not supported<commit_after>package runtime_test

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

func checkGdbPython(t *testing.T) {
	cmd := exec.Command("gdb", "-nx", "-q", "--batch", "-iex", "python import sys; print('go gdb python support')")
	out, err := cmd.CombinedOutput()

	if err != nil {
		t.Skipf("skipping due to issue running gdb: %v", err)
	}
	if string(out) != "go gdb python support\n" {
		t.Skipf("skipping due to lack of python gdb support: %s", out)
	}
}

const helloSource = `
package main
import "fmt"
func main() {
	fmt.Println("hi")
}
`

func TestGdbLoadRuntimeSupport(t *testing.T) {
	checkGdbPython(t)

	dir, err := ioutil.TempDir("", "go-build")
	if err != nil {
		t.Fatalf("failed to create temp directory: %v", err)
	}
	defer os.RemoveAll(dir)

	src := filepath.Join(dir, "main.go")
	err = ioutil.WriteFile(src, []byte(helloSource), 0644)
	if err != nil {
		t.Fatalf("failed to create file: %v", err)
	}

	cmd := exec.Command("go", "build", "-o", "a.exe")
	cmd.Dir = dir
	out, err := cmd.CombinedOutput()
	if err != nil {
		t.Fatalf("building source %v\n%s", err, out)
	}

	got, _ := exec.Command("gdb", "-nx", "-q", "--batch", "-iex",
		fmt.Sprintf("add-auto-load-safe-path %s/src/runtime", runtime.GOROOT()),
		filepath.Join(dir, "a.exe")).CombinedOutput()
	if string(got) != "Loading Go Runtime support.\n" {
		t.Fatalf("%s", got)
	}
}
<|endoftext|>


<commit_before>package vizzini_test

import (
	"time"

	"code.cloudfoundry.org/bbs/models"
	. "code.cloudfoundry.org/vizzini/matchers"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Privileged", func() {
	var task *models.TaskDefinition
	var runUser string
	var containerPrivileged bool

	BeforeEach(func() {
		if !enablePrivilegedContainerTests {
			Skip("privileged container tests are disabled")
		}
		if timeout == DefaultEventuallyTimeout {
			SetDefaultEventuallyTimeout(time.Second * 15)
		}
	})

	JustBeforeEach(func() {
		task = Task()
		task.Privileged = containerPrivileged
		task.Action = models.WrapAction(&models.RunAction{
			Path: "bash",
			Args: []string{"-c", "id > /tmp/bar; echo h > /proc/sysrq-trigger ; echo have_real_root=$? >> /tmp/bar"},
			User: runUser,
		})

		Expect(bbsClient.DesireTask(logger, guid, domain, task)).To(Succeed())
		Eventually(TaskGetter(logger, guid)).Should(HaveTaskState(models.Task_Completed))
	})

	AfterEach(func() {
		defer SetDefaultEventuallyTimeout(timeout)
		Expect(bbsClient.ResolvingTask(logger, guid)).To(Succeed())
		Expect(bbsClient.DeleteTask(logger, guid)).To(Succeed())
	})

	Context("with a privileged container", func() {
		BeforeEach(func() {
			containerPrivileged = true
		})

		Context("when running a privileged action", func() {
			BeforeEach(func() {
				runUser = "root"
			})

			It("should run as root", func() {
				completedTask, err := bbsClient.TaskByGuid(logger, guid)
				Expect(err).NotTo(HaveOccurred())
				Expect(completedTask.Result).To(ContainSubstring("uid=0(root)"), "If this fails, then your executor may not be configured to allow privileged actions")
				Expect(completedTask.Result).To(MatchRegexp(`groups=.*0\(root\)`))
				Expect(completedTask.Result).To(ContainSubstring("have_real_root=0"))
			})
		})

		Context("when running a non-privileged action", func() {
			BeforeEach(func() {
				runUser = "vcap"
			})

			It("should run as non-root", func() {
				completedTask, err := bbsClient.TaskByGuid(logger, guid)
				Expect(err).NotTo(HaveOccurred())
				Expect(completedTask.Result).To(MatchRegexp(`uid=\d{4,5}\(vcap\)`))
				Expect(completedTask.Result).To(MatchRegexp(`groups=\d{4,5}\(vcap\)`))
				Expect(completedTask.Result).To(ContainSubstring("have_real_root=1"))
			})
		})
	})

	Context("with an unprivileged container", func() {
		BeforeEach(func() {
			containerPrivileged = false
		})

		Context("when running a privileged action", func() {
			BeforeEach(func() {
				runUser = "root"
			})

			It("should run as namespaced root", func() {
				completedTask, err := bbsClient.TaskByGuid(logger, guid)
				Expect(err).NotTo(HaveOccurred())
				Expect(completedTask.Result).To(ContainSubstring("uid=0(root)"), "If this fails, then your executor may not be configured to allow privileged actions")
				Expect(completedTask.Result).To(ContainSubstring("have_real_root=1"))
			})
		})

		Context("when running a non-privileged action", func() {
			BeforeEach(func() {
				runUser = "vcap"
			})

			It("should run as non-root", func() {
				completedTask, err := bbsClient.TaskByGuid(logger, guid)
				Expect(err).NotTo(HaveOccurred())
				Expect(completedTask.Result).To(MatchRegexp(`uid=\d{4,5}\(vcap\)`))
				Expect(completedTask.Result).To(ContainSubstring("have_real_root=1"))
			})
		})
	})
})
<commit_msg>only skip the privileged container test<commit_after>package vizzini_test

import (
	"time"

	"code.cloudfoundry.org/bbs/models"
	. "code.cloudfoundry.org/vizzini/matchers"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Privileged", func() {
	var task *models.TaskDefinition
	var runUser string
	var containerPrivileged bool

	BeforeEach(func() {
		if timeout == DefaultEventuallyTimeout {
			SetDefaultEventuallyTimeout(time.Second * 15)
		}
	})

	JustBeforeEach(func() {
		task = Task()
		task.Privileged = containerPrivileged
		task.Action = models.WrapAction(&models.RunAction{
			Path: "bash",
			Args: []string{"-c", "id > /tmp/bar; echo h > /proc/sysrq-trigger ; echo have_real_root=$? >> /tmp/bar"},
			User: runUser,
		})

		Expect(bbsClient.DesireTask(logger, guid, domain, task)).To(Succeed())
		Eventually(TaskGetter(logger, guid)).Should(HaveTaskState(models.Task_Completed))
	})

	AfterEach(func() {
		defer SetDefaultEventuallyTimeout(timeout)
		Expect(bbsClient.ResolvingTask(logger, guid)).To(Succeed())
		Expect(bbsClient.DeleteTask(logger, guid)).To(Succeed())
	})

	Context("with a privileged container", func() {
		BeforeEach(func() {
			if !enablePrivilegedContainerTests {
				Skip("privileged container tests are disabled")
			}

			containerPrivileged = true
		})

		Context("when running a privileged action", func() {
			BeforeEach(func() {
				runUser = "root"
			})

			It("should run as root", func() {
				completedTask, err := bbsClient.TaskByGuid(logger, guid)
				Expect(err).NotTo(HaveOccurred())
				Expect(completedTask.Result).To(ContainSubstring("uid=0(root)"), "If this fails, then your executor may not be configured to allow privileged actions")
				Expect(completedTask.Result).To(MatchRegexp(`groups=.*0\(root\)`))
				Expect(completedTask.Result).To(ContainSubstring("have_real_root=0"))
			})
		})

		Context("when running a non-privileged action", func() {
			BeforeEach(func() {
				runUser = "vcap"
			})

			It("should run as non-root", func() {
				completedTask, err := bbsClient.TaskByGuid(logger, guid)
				Expect(err).NotTo(HaveOccurred())
				Expect(completedTask.Result).To(MatchRegexp(`uid=\d{4,5}\(vcap\)`))
				Expect(completedTask.Result).To(MatchRegexp(`groups=\d{4,5}\(vcap\)`))
				Expect(completedTask.Result).To(ContainSubstring("have_real_root=1"))
			})
		})
	})

	Context("with an unprivileged container", func() {
		BeforeEach(func() {
			containerPrivileged = false
		})

		Context("when running a privileged action", func() {
			BeforeEach(func() {
				runUser = "root"
			})

			It("should run as namespaced root", func() {
				completedTask, err := bbsClient.TaskByGuid(logger, guid)
				Expect(err).NotTo(HaveOccurred())
				Expect(completedTask.Result).To(ContainSubstring("uid=0(root)"), "If this fails, then your executor may not be configured to allow privileged actions")
				Expect(completedTask.Result).To(ContainSubstring("have_real_root=1"))
			})
		})

		Context("when running a non-privileged action", func() {
			BeforeEach(func() {
				runUser = "vcap"
			})

			It("should run as non-root", func() {
				completedTask, err := bbsClient.TaskByGuid(logger, guid)
				Expect(err).NotTo(HaveOccurred())
				Expect(completedTask.Result).To(MatchRegexp(`uid=\d{4,5}\(vcap\)`))
				Expect(completedTask.Result).To(ContainSubstring("have_real_root=1"))
			})
		})
	})
})
<|endoftext|>


<commit_before>// Copyright (c) 2014-2016 Bitmark Inc.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package proof

import (
	"bytes"
	"crypto/rand"
	"encoding/binary"
	"encoding/json"
	"fmt"
	"github.com/bitmark-inc/bitmarkd/account"
	"github.com/bitmark-inc/bitmarkd/asset"
	"github.com/bitmark-inc/bitmarkd/block"
	"github.com/bitmark-inc/bitmarkd/blockrecord"
	"github.com/bitmark-inc/bitmarkd/currency"
	"github.com/bitmark-inc/bitmarkd/difficulty"
	"github.com/bitmark-inc/bitmarkd/fault"
	"github.com/bitmark-inc/bitmarkd/merkle"
	"github.com/bitmark-inc/bitmarkd/mode"
	"github.com/bitmark-inc/bitmarkd/reservoir"
	"github.com/bitmark-inc/bitmarkd/storage"
	"github.com/bitmark-inc/bitmarkd/transactionrecord"
	"github.com/bitmark-inc/bitmarkd/util"
	"github.com/bitmark-inc/bitmarkd/zmqutil"
	"github.com/bitmark-inc/logger"
	zmq "github.com/pebbe/zmq4"
	"golang.org/x/crypto/ed25519"
	"io/ioutil"
	"time"
)

const (
	publishInterval    = 60 * time.Second
	publisherZapDomain = "publisher"
)

type publisher struct {
	log             *logger.L
	socket4         *zmq.Socket
	socket6         *zmq.Socket
	paymentCurrency currency.Currency
	paymentAddress  string
	owner           *account.Account
	privateKey      []byte
}

// initialise the publisher
func (pub *publisher) initialise(configuration *Configuration) error {

	log := logger.New("publisher")
	if nil == log {
		return fault.ErrInvalidLoggerChannel
	}
	pub.log = log

	log.Info("initialising…")

	_, err := fmt.Sscan(configuration.Currency, &pub.paymentCurrency)
	if nil != err {
		log.Errorf("currency: %q  error: %v", configuration.Currency, err)
		return err
	}
	pub.paymentAddress = configuration.Address

	if databytes, err := ioutil.ReadFile(configuration.SigningKey); err != nil {
		return err
	} else {
		rand := bytes.NewBuffer(databytes)
		publicKey, privateKey, err := ed25519.GenerateKey(rand)
		if nil != err {
			log.Errorf("public key generation  error: %v", err)
			return err
		}
		pub.owner = &account.Account{
			AccountInterface: &account.ED25519Account{
				Test:      true,
				PublicKey: publicKey,
			},
		}
		pub.privateKey = privateKey
	}

	// read the keys
	privateKey, err := zmqutil.ReadPrivateKeyFile(configuration.PrivateKey)
	if nil != err {
		log.Errorf("read private key file: %q  error: %v", configuration.PrivateKey, err)
		return err
	}
	publicKey, err := zmqutil.ReadPublicKeyFile(configuration.PublicKey)
	if nil != err {
		log.Errorf("read public key file: %q  error: %v", configuration.PublicKey, err)
		return err
	}
	log.Tracef("server public:  %x", publicKey)
	log.Tracef("server private: %x", privateKey)

	// create connections
	c, err := util.NewConnections(configuration.Publish)

	// allocate IPv4 and IPv6 sockets
	pub.socket4, pub.socket6, err = zmqutil.NewBind(log, zmq.PUB, publisherZapDomain, privateKey, publicKey, c)
	if nil != err {
		log.Errorf("bind error: %v", err)
		return err
	}

	return nil
}

// wait for new blocks or new payment items
// to ensure the queue integrity as heap is not thread-safe
func (pub *publisher) Run(args interface{}, shutdown <-chan struct{}) {

	log := pub.log

	log.Info("starting…")

loop:
	for {
		log.Info("waiting…")
		select {
		case <-shutdown:
			break loop
		case <-time.After(publishInterval):
			pub.process()
		}
	}
	if nil != pub.socket4 {
		pub.socket4.Close()
	}
	if nil != pub.socket6 {
		pub.socket6.Close()
	}
}

// process some items into a block and publish it
func (pub *publisher) process() {

	// only create new blocks if in normal mode
	if !mode.Is(mode.Normal) {
		return
	}

	seenAsset := make(map[transactionrecord.AssetIndex]struct{})

	txIds, transactions, totalByteCount, err := reservoir.Fetch(blockrecord.MaximumTransactions)
	if nil != err {
		pub.log.Errorf("Error on Fetch: %v", err)
		return
	}

	txCount := len(txIds)

	if 0 == txCount {
		pub.log.Info("verified pool is empty")
		return
	}

	// buffer to concatenate all transaction data
	txData := make([]byte, 0, totalByteCount)

	// to accumulate new assets
	assetIds := make([]transactionrecord.AssetIndex, 0, txCount)

	base := &transactionrecord.BaseData{
		Currency:       pub.paymentCurrency,
		PaymentAddress: pub.paymentAddress,
		Owner:          pub.owner,
		Nonce:          1234,
	}

	// sign the record and attach signature
	partiallyPackedBase, _ := base.Pack(pub.owner) // ignore error to get packed without signature
	signature := ed25519.Sign(pub.privateKey[:], partiallyPackedBase)
	base.Signature = signature[:]

	// re-pack to makesure signature is valid
	packedBase, err := base.Pack(pub.owner)
	if nil != err {
		pub.log.Criticalf("pack base error: %v", err)
		fault.PanicWithError("publisher packe base", err)
	}

	// first txId is the base
	txIds = append([]merkle.Digest{merkle.NewDigest(packedBase)}, txIds...)

	for _, item := range transactions {
		unpacked, _, err := transactionrecord.Packed(item).Unpack()
		if nil != err {
			pub.log.Criticalf("unpack error: %v", err)
			fault.PanicWithError("publisher extraction transactions", err)
		}

		// only issues and transfers are allowed here
		switch tx := unpacked.(type) {
		case *transactionrecord.BitmarkIssue:

			if _, ok := seenAsset[tx.AssetIndex]; !ok {
				if !storage.Pool.Assets.Has(tx.AssetIndex[:]) {

					packedAsset := asset.Get(tx.AssetIndex)
					if nil == packedAsset {
						pub.log.Criticalf("missing asset: %v", tx.AssetIndex)
						fault.Panicf("publisher missing asset: %v", tx.AssetIndex)
					}
					// add asset's transaction id to list
					txId := merkle.NewDigest(packedAsset)
					txIds = append(txIds, txId)
					assetIds = append(assetIds, tx.AssetIndex)
					txData = append(txData, packedAsset...)
				}
				seenAsset[tx.AssetIndex] = struct{}{}
			}

		case *transactionrecord.BitmarkTransfer:
			// ok

		default: // all other types cannot occur here
			pub.log.Criticalf("unxpected transaction: %v", unpacked)
			fault.Panicf("publisher unxpected transaction: %v", unpacked)
		}

		txData = append(txData, item...)
	}

	// build the tree of transaction IDs
	fullMerkleTree := merkle.FullMerkleTree(txIds)
	merkleRoot := fullMerkleTree[len(fullMerkleTree)-1]

	transactionCount := len(txIds)
	if transactionCount > blockrecord.MaximumTransactions {
		pub.log.Criticalf("too many transactions in block: %d", transactionCount)
		fault.Panicf("too many transactions in blok: %d", transactionCount)
	}

	// 64 bit nonce (8 bytes)
	randomBytes := make([]byte, 8)
	_, err = rand.Read(randomBytes)
	nonce := blockrecord.NonceType(binary.LittleEndian.Uint64(randomBytes))

	bits := difficulty.Current
	timestamp := uint64(time.Now().Unix())

	// PreviousBlock is all zero
	message := &PublishedItem{
		Job: "?", // set by enqueue
		Header: blockrecord.Header{
			Version:          blockrecord.Version,
			TransactionCount: uint16(transactionCount),
			MerkleRoot:       merkleRoot,
			Timestamp:        timestamp,
			Difficulty:       bits,
			Nonce:            nonce,
		},
		Base:     packedBase,
		TxIds:    txIds,
		AssetIds: assetIds,
	}
	message.Header.PreviousBlock, message.Header.Number = block.Get()

	// add job to the queue
	enqueueToJobQueue(message, txData)

	data, err := json.Marshal(message)
	fault.PanicIfError("JSON encode error: %v", err)

	pub.log.Infof("json to send: %s", data)

	// ***** FIX THIS: is the DONTWAIT flag needed or not?
	if nil != pub.socket4 {
		_, err = pub.socket4.SendBytes(data, 0|zmq.DONTWAIT)
		fault.PanicIfError("publisher 4", err)
	}
	if nil != pub.socket6 {
		_, err = pub.socket6.SendBytes(data, 0|zmq.DONTWAIT)
		fault.PanicIfError("publisher 6", err)
	}

	time.Sleep(10 * time.Second)
}
<commit_msg>[proof] fix the ordering of TxIds when asset is inserted<commit_after>// Copyright (c) 2014-2016 Bitmark Inc.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package proof

import (
	"bytes"
	"crypto/rand"
	"encoding/binary"
	"encoding/json"
	"fmt"
	"github.com/bitmark-inc/bitmarkd/account"
	"github.com/bitmark-inc/bitmarkd/asset"
	"github.com/bitmark-inc/bitmarkd/block"
	"github.com/bitmark-inc/bitmarkd/blockrecord"
	"github.com/bitmark-inc/bitmarkd/currency"
	"github.com/bitmark-inc/bitmarkd/difficulty"
	"github.com/bitmark-inc/bitmarkd/fault"
	"github.com/bitmark-inc/bitmarkd/merkle"
	"github.com/bitmark-inc/bitmarkd/mode"
	"github.com/bitmark-inc/bitmarkd/reservoir"
	"github.com/bitmark-inc/bitmarkd/storage"
	"github.com/bitmark-inc/bitmarkd/transactionrecord"
	"github.com/bitmark-inc/bitmarkd/util"
	"github.com/bitmark-inc/bitmarkd/zmqutil"
	"github.com/bitmark-inc/logger"
	zmq "github.com/pebbe/zmq4"
	"golang.org/x/crypto/ed25519"
	"io/ioutil"
	"time"
)

const (
	publishInterval    = 60 * time.Second
	publisherZapDomain = "publisher"
)

type publisher struct {
	log             *logger.L
	socket4         *zmq.Socket
	socket6         *zmq.Socket
	paymentCurrency currency.Currency
	paymentAddress  string
	owner           *account.Account
	privateKey      []byte
}

// initialise the publisher
func (pub *publisher) initialise(configuration *Configuration) error {

	log := logger.New("publisher")
	if nil == log {
		return fault.ErrInvalidLoggerChannel
	}
	pub.log = log

	log.Info("initialising…")

	_, err := fmt.Sscan(configuration.Currency, &pub.paymentCurrency)
	if nil != err {
		log.Errorf("currency: %q  error: %v", configuration.Currency, err)
		return err
	}
	pub.paymentAddress = configuration.Address

	if databytes, err := ioutil.ReadFile(configuration.SigningKey); err != nil {
		return err
	} else {
		rand := bytes.NewBuffer(databytes)
		publicKey, privateKey, err := ed25519.GenerateKey(rand)
		if nil != err {
			log.Errorf("public key generation  error: %v", err)
			return err
		}
		pub.owner = &account.Account{
			AccountInterface: &account.ED25519Account{
				Test:      true,
				PublicKey: publicKey,
			},
		}
		pub.privateKey = privateKey
	}

	// read the keys
	privateKey, err := zmqutil.ReadPrivateKeyFile(configuration.PrivateKey)
	if nil != err {
		log.Errorf("read private key file: %q  error: %v", configuration.PrivateKey, err)
		return err
	}
	publicKey, err := zmqutil.ReadPublicKeyFile(configuration.PublicKey)
	if nil != err {
		log.Errorf("read public key file: %q  error: %v", configuration.PublicKey, err)
		return err
	}
	log.Tracef("server public:  %x", publicKey)
	log.Tracef("server private: %x", privateKey)

	// create connections
	c, err := util.NewConnections(configuration.Publish)

	// allocate IPv4 and IPv6 sockets
	pub.socket4, pub.socket6, err = zmqutil.NewBind(log, zmq.PUB, publisherZapDomain, privateKey, publicKey, c)
	if nil != err {
		log.Errorf("bind error: %v", err)
		return err
	}

	return nil
}

// wait for new blocks or new payment items
// to ensure the queue integrity as heap is not thread-safe
func (pub *publisher) Run(args interface{}, shutdown <-chan struct{}) {

	log := pub.log

	log.Info("starting…")

loop:
	for {
		log.Info("waiting…")
		select {
		case <-shutdown:
			break loop
		case <-time.After(publishInterval):
			pub.process()
		}
	}
	if nil != pub.socket4 {
		pub.socket4.Close()
	}
	if nil != pub.socket6 {
		pub.socket6.Close()
	}
}

// process some items into a block and publish it
func (pub *publisher) process() {

	// only create new blocks if in normal mode
	if !mode.Is(mode.Normal) {
		return
	}

	seenAsset := make(map[transactionrecord.AssetIndex]struct{})

	pooledTxIds, transactions, totalByteCount, err := reservoir.Fetch(blockrecord.MaximumTransactions)
	if nil != err {
		pub.log.Errorf("Error on Fetch: %v", err)
		return
	}

	txCount := len(pooledTxIds)

	if 0 == txCount {
		pub.log.Info("verified pool is empty")
		return
	}

	// buffer to concatenate all transaction data
	txData := make([]byte, 0, totalByteCount)

	// to accumulate new assets
	assetIds := make([]transactionrecord.AssetIndex, 0, txCount)

	base := &transactionrecord.BaseData{
		Currency:       pub.paymentCurrency,
		PaymentAddress: pub.paymentAddress,
		Owner:          pub.owner,
		Nonce:          1234,
	}

	// sign the record and attach signature
	partiallyPackedBase, _ := base.Pack(pub.owner) // ignore error to get packed without signature
	signature := ed25519.Sign(pub.privateKey[:], partiallyPackedBase)
	base.Signature = signature[:]

	// re-pack to makesure signature is valid
	packedBase, err := base.Pack(pub.owner)
	if nil != err {
		pub.log.Criticalf("pack base error: %v", err)
		fault.PanicWithError("publisher packe base", err)
	}

	// first txId is the base
	txIds := make([]merkle.Digest, 1, len(pooledTxIds)*2) // allow room for inserted assets & allocate base
	txIds[0] = merkle.NewDigest(packedBase)               // base is first

	n := 0 // index for txIds
	for _, item := range transactions {
		unpacked, _, err := transactionrecord.Packed(item).Unpack()
		if nil != err {
			pub.log.Criticalf("unpack error: %v", err)
			fault.PanicWithError("publisher extraction transactions", err)
		}

		// only issues and transfers are allowed here
		switch tx := unpacked.(type) {
		case *transactionrecord.BitmarkIssue:

			if _, ok := seenAsset[tx.AssetIndex]; !ok {
				if !storage.Pool.Assets.Has(tx.AssetIndex[:]) {

					packedAsset := asset.Get(tx.AssetIndex)
					if nil == packedAsset {
						pub.log.Criticalf("missing asset: %v", tx.AssetIndex)
						fault.Panicf("publisher missing asset: %v", tx.AssetIndex)
					}
					// add asset's transaction id to list
					txId := merkle.NewDigest(packedAsset)
					txIds = append(txIds, txId)
					assetIds = append(assetIds, tx.AssetIndex)
					txData = append(txData, packedAsset...)
				}
				seenAsset[tx.AssetIndex] = struct{}{}
			}

		case *transactionrecord.BitmarkTransfer:
			// ok

		default: // all other types cannot occur here
			pub.log.Criticalf("unxpected transaction: %v", unpacked)
			fault.Panicf("publisher unxpected transaction: %v", unpacked)
		}

		// concatenate items
		txIds = append(txIds, pooledTxIds[n])
		txData = append(txData, item...)
		n += 1
	}

	// build the tree of transaction IDs
	fullMerkleTree := merkle.FullMerkleTree(txIds)
	merkleRoot := fullMerkleTree[len(fullMerkleTree)-1]

	transactionCount := len(txIds)
	if transactionCount > blockrecord.MaximumTransactions {
		pub.log.Criticalf("too many transactions in block: %d", transactionCount)
		fault.Panicf("too many transactions in block: %d", transactionCount)
	}

	// 64 bit nonce (8 bytes)
	randomBytes := make([]byte, 8)
	_, err = rand.Read(randomBytes)
	nonce := blockrecord.NonceType(binary.LittleEndian.Uint64(randomBytes))

	bits := difficulty.Current
	timestamp := uint64(time.Now().Unix())

	// PreviousBlock is all zero
	message := &PublishedItem{
		Job: "?", // set by enqueue
		Header: blockrecord.Header{
			Version:          blockrecord.Version,
			TransactionCount: uint16(transactionCount),
			MerkleRoot:       merkleRoot,
			Timestamp:        timestamp,
			Difficulty:       bits,
			Nonce:            nonce,
		},
		Base:     packedBase,
		TxIds:    txIds,
		AssetIds: assetIds,
	}

	pub.log.Tracef("message: %v", message)

	message.Header.PreviousBlock, message.Header.Number = block.Get()

	// add job to the queue
	enqueueToJobQueue(message, txData)

	data, err := json.Marshal(message)
	fault.PanicIfError("JSON encode error: %v", err)

	pub.log.Infof("json to send: %s", data)

	// ***** FIX THIS: is the DONTWAIT flag needed or not?
	if nil != pub.socket4 {
		_, err = pub.socket4.SendBytes(data, 0|zmq.DONTWAIT)
		fault.PanicIfError("publisher 4", err)
	}
	if nil != pub.socket6 {
		_, err = pub.socket6.SendBytes(data, 0|zmq.DONTWAIT)
		fault.PanicIfError("publisher 6", err)
	}

	time.Sleep(10 * time.Second)
}
<|endoftext|>


<commit_before>package main_test

import (
	"bufio"
	"os"
	"os/exec"
	"path/filepath"
	"time"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
)

var _ = Describe("main", func() {
	var (
		old_PLUGINS_HOME string
	)

	BeforeEach(func() {
		old_PLUGINS_HOME = os.Getenv("CF_PLUGIN_HOME")

		dir, err := os.Getwd()
		Expect(err).NotTo(HaveOccurred())

		fullDir := filepath.Join(dir, "..", "fixtures", "config", "main-plugin-test-config")
		err = os.Setenv("CF_PLUGIN_HOME", fullDir)
		Expect(err).NotTo(HaveOccurred())
	})

	AfterEach(func() {
		err := os.Setenv("CF_PLUGIN_HOME", old_PLUGINS_HOME)
		Expect(err).NotTo(HaveOccurred())
	})

	Describe("Help menu with -h/--help", func() {
		It("prints the help output with our custom template when run with 'cf -h'", func() {
			output := Cf("-h").Wait(1 * time.Second)
			Eventually(output.Out.Contents).Should(ContainSubstring("A command line tool to interact with Cloud Foundry"))
			Eventually(output.Out.Contents).Should(ContainSubstring("CF_TRACE=true"))
		})

		It("prints the help output with our custom template when run with 'cf --help'", func() {
			output := Cf("--help").Wait(1 * time.Second)
			Eventually(output.Out.Contents).Should(ContainSubstring("A command line tool to interact with Cloud Foundry"))
			Eventually(output.Out.Contents).Should(ContainSubstring("CF_TRACE=true"))
		})

		It("accepts -h and --h flags for all commands", func() {
			result := Cf("push", "-h")
			Consistently(result.Out).ShouldNot(Say("Incorrect Usage"))
			Consistently(result.Out).Should(Say("USAGE"))

			result = Cf("target", "--h")
			Consistently(result.Out).ShouldNot(Say("Incorrect Usage"))
			Consistently(result.Out).Should(Say("USAGE"))
		})

	})

	Describe("Shows version with -v", func() {
		It("prints the cf version if '-v' flag is provided", func() {
			output := Cf("-v").Wait(1 * time.Second)
			Eventually(output.Out.Contents).Should(ContainSubstring("version"))
			Ω(output.ExitCode()).To(Equal(0))
		})

		It("prints the help output with our custom template when run with 'cf --help'", func() {
			output := Cf("--help").Wait(1 * time.Second)
			Eventually(output.Out.Contents).Should(ContainSubstring("A command line tool to interact with Cloud Foundry"))
			Eventually(output.Out.Contents).Should(ContainSubstring("CF_TRACE=true"))
		})
	})

	Describe("Commands /w new non-codegangsta structure", func() {
		It("prints usage help for all non-codegangsta commands by providing `help` flag", func() {
			output := Cf("api", "-h").Wait(1 * time.Second)
			Eventually(output.Out.Contents).Should(ContainSubstring("USAGE"))
			Eventually(output.Out.Contents).Should(ContainSubstring("OPTIONS"))
		})

		It("accepts -h and --h flags for non-codegangsta commands", func() {
			result := Cf("api", "-h")
			Consistently(result.Out).ShouldNot(Say("Invalid flag: -h"))
			Eventually(result.Out.Contents).Should(ContainSubstring("api - Set or view target api url"))

			result = Cf("api", "--h")
			Consistently(result.Out).ShouldNot(Say("Invalid flag: --h"))
			Eventually(result.Out.Contents).Should(ContainSubstring("api - Set or view target api url"))
		})

		It("runs requirement of the non-codegangsta command", func() {
			dir, err := os.Getwd()
			Expect(err).ToNot(HaveOccurred())
			fullDir := filepath.Join(dir, "..", "fixtures") //set home to a config w/o targeted api
			result := CfWith_CF_HOME(fullDir, "app", "app-should-never-exist-blah-blah")

			Eventually(result.Out).Should(Say("No API endpoint set."))
		})
	})

	Describe("exit codes", func() {
		It("exits non-zero when an unknown command is invoked", func() {
			result := Cf("some-command-that-should-never-actually-be-a-real-thing-i-can-use")

			Eventually(result, 3*time.Second).Should(Say("not a registered command"))
			Eventually(result).Should(Exit(1))
		})

		It("exits non-zero when known command is invoked with invalid option", func() {
			result := Cf("push", "--crazy")
			Eventually(result).Should(Exit(1))
		})
	})

	It("can print help menu by executing only the command `cf`", func() {
		output := Cf().Wait(3 * time.Second)
		Eventually(output.Out.Contents).Should(ContainSubstring("A command line tool to interact with Cloud Foundry"))
	})

	Describe("Plugins", func() {
		It("Can call a plugin command from the Plugins configuration if it does not exist as a cf command", func() {
			output := Cf("test_1_cmd1").Wait(3 * time.Second)
			Eventually(output.Out).Should(Say("You called cmd1 in test_1"))
		})

		It("Can call a plugin command via alias if it does not exist as a cf command", func() {
			output := Cf("test_1_cmd1_alias").Wait(3 * time.Second)
			Eventually(output.Out).Should(Say("You called cmd1 in test_1"))
		})

		It("Can call another plugin command when more than one plugin is installed", func() {
			output := Cf("test_2_cmd1").Wait(3 * time.Second)
			Eventually(output.Out).Should(Say("You called cmd1 in test_2"))
		})

		It("informs user for any invalid commands", func() {
			output := Cf("foo-bar")
			Eventually(output.Out, 3*time.Second).Should(Say("'foo-bar' is not a registered command"))
		})

		It("Calls help if the plugin shares the same name", func() {
			output := Cf("help")
			Consistently(output.Out, 1).ShouldNot(Say("You called help in test_with_help"))
		})

		It("shows help with a '-h' or '--help' flag in plugin command", func() {
			output := Cf("test_1_cmd1", "-h").Wait(3 * time.Second)
			Eventually(output.Out).ShouldNot(Say("You called cmd1 in test_1"))
			Eventually(output.Out.Contents).Should(ContainSubstring("USAGE:"))
			Eventually(output.Out.Contents).Should(ContainSubstring("OPTIONS:"))
		})

		It("Calls the core push command if the plugin shares the same name", func() {
			output := Cf("push")
			Consistently(output.Out, 1).ShouldNot(Say("You called push in test_with_push"))
		})

		It("Calls the core short name if a plugin shares the same name", func() {
			output := Cf("p")
			Consistently(output.Out, 1).ShouldNot(Say("You called p within the plugin"))
		})

		It("Passes all arguments to a plugin", func() {
			output := Cf("my-say", "foo").Wait(3 * time.Second)
			Eventually(output.Out).Should(Say("foo"))
		})

		It("Passes all arguments and flags to a plugin", func() {
			output := Cf("my-say", "foo", "--loud").Wait(3 * time.Second)
			Eventually(output.Out).Should(Say("FOO"))
		})

		It("Calls a plugin that calls core commands", func() {
			output := Cf("awesomeness").Wait(3 * time.Second)
			Eventually(output.Out).Should(Say("my-say")) //look for another plugin
		})

		It("Sends stdoutput to the plugin to echo", func() {
			output := Cf("core-command", "plugins").Wait(3 * time.Second)
			Eventually(output.Out.Contents).Should(MatchRegexp("Command output from the plugin(.*\\W)*awesomeness(.*\\W)*FIN"))
		})

		It("Can call a core commmand from a plugin without terminal output", func() {
			output := Cf("core-command-quiet", "plugins").Wait(3 * time.Second)
			Eventually(output.Out.Contents).Should(MatchRegexp("^\n---------- Command output from the plugin"))
		})

		It("Can call a plugin that requires stdin (interactive)", func() {
			session := CfWithIo("input", "silly\n").Wait(5 * time.Second)
			Eventually(session.Out).Should(Say("silly"))
		})

		It("exits 1 when a plugin panics", func() {
			session := Cf("panic").Wait(5 * time.Second)
			Eventually(session).Should(Exit(1))
		})

		It("exits 1 when a plugin exits 1", func() {
			session := Cf("exit1").Wait(5 * time.Second)
			Eventually(session).Should(Exit(1))
		})
	})

})

func Cf(args ...string) *Session {
	path, err := Build("github.com/cloudfoundry/cli/main")
	Expect(err).NotTo(HaveOccurred())

	session, err := Start(exec.Command(path, args...), GinkgoWriter, GinkgoWriter)
	Expect(err).NotTo(HaveOccurred())

	return session
}
func CfWithIo(command string, args string) *Session {
	path, err := Build("github.com/cloudfoundry/cli/main")
	Expect(err).NotTo(HaveOccurred())

	cmd := exec.Command(path, command)

	stdin, err := cmd.StdinPipe()
	Expect(err).ToNot(HaveOccurred())

	buffer := bufio.NewWriter(stdin)
	buffer.WriteString(args)
	buffer.Flush()

	session, err := Start(cmd, GinkgoWriter, GinkgoWriter)
	Expect(err).NotTo(HaveOccurred())

	return session
}
func CfWith_CF_HOME(cfHome string, args ...string) *Session {
	path, err := Build("github.com/cloudfoundry/cli/main")
	Expect(err).NotTo(HaveOccurred())

	cmd := exec.Command(path, args...)
	cmd.Env = append(cmd.Env, "CF_HOME="+cfHome)
	session, err := Start(cmd, GinkgoWriter, GinkgoWriter)
	Expect(err).NotTo(HaveOccurred())

	return session
}

// gexec.Build leaves a compiled binary behind in /tmp.
var _ = AfterSuite(func() {
	CleanupBuildArtifacts()
})
<commit_msg>remove extra test<commit_after>package main_test

import (
	"bufio"
	"os"
	"os/exec"
	"path/filepath"
	"time"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
)

var _ = Describe("main", func() {
	var (
		old_PLUGINS_HOME string
	)

	BeforeEach(func() {
		old_PLUGINS_HOME = os.Getenv("CF_PLUGIN_HOME")

		dir, err := os.Getwd()
		Expect(err).NotTo(HaveOccurred())

		fullDir := filepath.Join(dir, "..", "fixtures", "config", "main-plugin-test-config")
		err = os.Setenv("CF_PLUGIN_HOME", fullDir)
		Expect(err).NotTo(HaveOccurred())
	})

	AfterEach(func() {
		err := os.Setenv("CF_PLUGIN_HOME", old_PLUGINS_HOME)
		Expect(err).NotTo(HaveOccurred())
	})

	Describe("Help menu with -h/--help", func() {
		It("prints the help output with our custom template when run with 'cf -h'", func() {
			output := Cf("-h").Wait(1 * time.Second)
			Eventually(output.Out.Contents).Should(ContainSubstring("A command line tool to interact with Cloud Foundry"))
			Eventually(output.Out.Contents).Should(ContainSubstring("CF_TRACE=true"))
		})

		It("prints the help output with our custom template when run with 'cf --help'", func() {
			output := Cf("--help").Wait(1 * time.Second)
			Eventually(output.Out.Contents).Should(ContainSubstring("A command line tool to interact with Cloud Foundry"))
			Eventually(output.Out.Contents).Should(ContainSubstring("CF_TRACE=true"))
		})

		It("accepts -h and --h flags for all commands", func() {
			result := Cf("push", "-h")
			Consistently(result.Out).ShouldNot(Say("Incorrect Usage"))
			Consistently(result.Out).Should(Say("USAGE"))

			result = Cf("target", "--h")
			Consistently(result.Out).ShouldNot(Say("Incorrect Usage"))
			Consistently(result.Out).Should(Say("USAGE"))
		})

	})

	Describe("Shows version with -v", func() {
		It("prints the cf version if '-v' flag is provided", func() {
			output := Cf("-v").Wait(1 * time.Second)
			Eventually(output.Out.Contents).Should(ContainSubstring("version"))
			Ω(output.ExitCode()).To(Equal(0))
		})
	})

	Describe("Commands /w new non-codegangsta structure", func() {
		It("prints usage help for all non-codegangsta commands by providing `help` flag", func() {
			output := Cf("api", "-h").Wait(1 * time.Second)
			Eventually(output.Out.Contents).Should(ContainSubstring("USAGE"))
			Eventually(output.Out.Contents).Should(ContainSubstring("OPTIONS"))
		})

		It("accepts -h and --h flags for non-codegangsta commands", func() {
			result := Cf("api", "-h")
			Consistently(result.Out).ShouldNot(Say("Invalid flag: -h"))
			Eventually(result.Out.Contents).Should(ContainSubstring("api - Set or view target api url"))

			result = Cf("api", "--h")
			Consistently(result.Out).ShouldNot(Say("Invalid flag: --h"))
			Eventually(result.Out.Contents).Should(ContainSubstring("api - Set or view target api url"))
		})

		It("runs requirement of the non-codegangsta command", func() {
			dir, err := os.Getwd()
			Expect(err).ToNot(HaveOccurred())
			fullDir := filepath.Join(dir, "..", "fixtures") //set home to a config w/o targeted api
			result := CfWith_CF_HOME(fullDir, "app", "app-should-never-exist-blah-blah")

			Eventually(result.Out).Should(Say("No API endpoint set."))
		})
	})

	Describe("exit codes", func() {
		It("exits non-zero when an unknown command is invoked", func() {
			result := Cf("some-command-that-should-never-actually-be-a-real-thing-i-can-use")

			Eventually(result, 3*time.Second).Should(Say("not a registered command"))
			Eventually(result).Should(Exit(1))
		})

		It("exits non-zero when known command is invoked with invalid option", func() {
			result := Cf("push", "--crazy")
			Eventually(result).Should(Exit(1))
		})
	})

	It("can print help menu by executing only the command `cf`", func() {
		output := Cf().Wait(3 * time.Second)
		Eventually(output.Out.Contents).Should(ContainSubstring("A command line tool to interact with Cloud Foundry"))
	})

	Describe("Plugins", func() {
		It("Can call a plugin command from the Plugins configuration if it does not exist as a cf command", func() {
			output := Cf("test_1_cmd1").Wait(3 * time.Second)
			Eventually(output.Out).Should(Say("You called cmd1 in test_1"))
		})

		It("Can call a plugin command via alias if it does not exist as a cf command", func() {
			output := Cf("test_1_cmd1_alias").Wait(3 * time.Second)
			Eventually(output.Out).Should(Say("You called cmd1 in test_1"))
		})

		It("Can call another plugin command when more than one plugin is installed", func() {
			output := Cf("test_2_cmd1").Wait(3 * time.Second)
			Eventually(output.Out).Should(Say("You called cmd1 in test_2"))
		})

		It("informs user for any invalid commands", func() {
			output := Cf("foo-bar")
			Eventually(output.Out, 3*time.Second).Should(Say("'foo-bar' is not a registered command"))
		})

		It("Calls help if the plugin shares the same name", func() {
			output := Cf("help")
			Consistently(output.Out, 1).ShouldNot(Say("You called help in test_with_help"))
		})

		It("shows help with a '-h' or '--help' flag in plugin command", func() {
			output := Cf("test_1_cmd1", "-h").Wait(3 * time.Second)
			Eventually(output.Out).ShouldNot(Say("You called cmd1 in test_1"))
			Eventually(output.Out.Contents).Should(ContainSubstring("USAGE:"))
			Eventually(output.Out.Contents).Should(ContainSubstring("OPTIONS:"))
		})

		It("Calls the core push command if the plugin shares the same name", func() {
			output := Cf("push")
			Consistently(output.Out, 1).ShouldNot(Say("You called push in test_with_push"))
		})

		It("Calls the core short name if a plugin shares the same name", func() {
			output := Cf("p")
			Consistently(output.Out, 1).ShouldNot(Say("You called p within the plugin"))
		})

		It("Passes all arguments to a plugin", func() {
			output := Cf("my-say", "foo").Wait(3 * time.Second)
			Eventually(output.Out).Should(Say("foo"))
		})

		It("Passes all arguments and flags to a plugin", func() {
			output := Cf("my-say", "foo", "--loud").Wait(3 * time.Second)
			Eventually(output.Out).Should(Say("FOO"))
		})

		It("Calls a plugin that calls core commands", func() {
			output := Cf("awesomeness").Wait(3 * time.Second)
			Eventually(output.Out).Should(Say("my-say")) //look for another plugin
		})

		It("Sends stdoutput to the plugin to echo", func() {
			output := Cf("core-command", "plugins").Wait(3 * time.Second)
			Eventually(output.Out.Contents).Should(MatchRegexp("Command output from the plugin(.*\\W)*awesomeness(.*\\W)*FIN"))
		})

		It("Can call a core commmand from a plugin without terminal output", func() {
			output := Cf("core-command-quiet", "plugins").Wait(3 * time.Second)
			Eventually(output.Out.Contents).Should(MatchRegexp("^\n---------- Command output from the plugin"))
		})

		It("Can call a plugin that requires stdin (interactive)", func() {
			session := CfWithIo("input", "silly\n").Wait(5 * time.Second)
			Eventually(session.Out).Should(Say("silly"))
		})

		It("exits 1 when a plugin panics", func() {
			session := Cf("panic").Wait(5 * time.Second)
			Eventually(session).Should(Exit(1))
		})

		It("exits 1 when a plugin exits 1", func() {
			session := Cf("exit1").Wait(5 * time.Second)
			Eventually(session).Should(Exit(1))
		})
	})

})

func Cf(args ...string) *Session {
	path, err := Build("github.com/cloudfoundry/cli/main")
	Expect(err).NotTo(HaveOccurred())

	session, err := Start(exec.Command(path, args...), GinkgoWriter, GinkgoWriter)
	Expect(err).NotTo(HaveOccurred())

	return session
}
func CfWithIo(command string, args string) *Session {
	path, err := Build("github.com/cloudfoundry/cli/main")
	Expect(err).NotTo(HaveOccurred())

	cmd := exec.Command(path, command)

	stdin, err := cmd.StdinPipe()
	Expect(err).ToNot(HaveOccurred())

	buffer := bufio.NewWriter(stdin)
	buffer.WriteString(args)
	buffer.Flush()

	session, err := Start(cmd, GinkgoWriter, GinkgoWriter)
	Expect(err).NotTo(HaveOccurred())

	return session
}
func CfWith_CF_HOME(cfHome string, args ...string) *Session {
	path, err := Build("github.com/cloudfoundry/cli/main")
	Expect(err).NotTo(HaveOccurred())

	cmd := exec.Command(path, args...)
	cmd.Env = append(cmd.Env, "CF_HOME="+cfHome)
	session, err := Start(cmd, GinkgoWriter, GinkgoWriter)
	Expect(err).NotTo(HaveOccurred())

	return session
}

// gexec.Build leaves a compiled binary behind in /tmp.
var _ = AfterSuite(func() {
	CleanupBuildArtifacts()
})
<|endoftext|>


<commit_before>package convey

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"github.com/stretchr/testify/assert"
	"io/ioutil"
	"testing"
)

// payloadTestData can be generated with:
// https://play.golang.org/p/Dn_wIn1Y14
var payloadTestData = []struct {
	encoding *base64.Encoding
	value    string
	expected Payload
}{
	{
		encoding: base64.StdEncoding,
		value:    "eyAicGFyYW1ldGVycyI6IFsgeyAibmFtZSI6ICJEZXZpY2UuRGV2aWNlSW5mby5XZWJwYS5YX0NPTUNBU1QtQ09NX0NJRCIsICJ2YWx1ZSI6ICIwIiwgImRhdGFUeXBlIjogMCB9LCB7ICJuYW1lIjogIkRldmljZS5EZXZpY2VJbmZvLldlYnBhLlhfQ09NQ0FTVC1DT01fQ01DIiwgInZhbHVlIjogIjI2OSIsICJkYXRhVHlwZSI6IDIgfSBdIH0K",
		expected: Payload{
			"parameters": []Payload{
				Payload{
					"name":     "Device.DeviceInfo.Webpa.X_COMCAST-COM_CID",
					"value":    "0",
					"dataType": 0,
				},
				Payload{
					"name":     "Device.DeviceInfo.Webpa.X_COMCAST-COM_CMC",
					"value":    "269",
					"dataType": 2,
				},
			},
		},
	},
	{
		encoding: base64.RawURLEncoding,
		value:    "eyJwYXJhbWV0ZXJzIjpbeyJkYXRhVHlwZSI6MCwibmFtZSI6IkRldmljZS5EZXZpY2VJbmZvLldlYnBhLlhfQ09NQ0FTVC1DT01fQ0lEIiwidmFsdWUiOiIwIn0seyJkYXRhVHlwZSI6MiwibmFtZSI6IkRldmljZS5EZXZpY2VJbmZvLldlYnBhLlhfQ09NQ0FTVC1DT01fQ01DIiwidmFsdWUiOiIyNjkifV19",
		expected: Payload{
			"parameters": []Payload{
				Payload{
					"name":     "Device.DeviceInfo.Webpa.X_COMCAST-COM_CID",
					"value":    "0",
					"dataType": 0,
				},
				Payload{
					"name":     "Device.DeviceInfo.Webpa.X_COMCAST-COM_CMC",
					"value":    "269",
					"dataType": 2,
				},
			},
		},
	},
	{
		encoding: base64.URLEncoding,
		value:    "eyJwYXJhbWV0ZXJzIjpbeyJkYXRhVHlwZSI6MCwibmFtZSI6IkRldmljZS5EZXZpY2VJbmZvLldlYnBhLlhfQ09NQ0FTVC1DT01fQ0lEIiwidmFsdWUiOiIwIn0seyJkYXRhVHlwZSI6MiwibmFtZSI6IkRldmljZS5EZXZpY2VJbmZvLldlYnBhLlhfQ09NQ0FTVC1DT01fQ01DIiwidmFsdWUiOiIyNjkifV19",
		expected: Payload{
			"parameters": []Payload{
				Payload{
					"name":     "Device.DeviceInfo.Webpa.X_COMCAST-COM_CID",
					"value":    "0",
					"dataType": 0,
				},
				Payload{
					"name":     "Device.DeviceInfo.Webpa.X_COMCAST-COM_CMC",
					"value":    "269",
					"dataType": 2,
				},
			},
		},
	},
	{
		encoding: base64.RawStdEncoding,
		value:    "eyJwYXJhbWV0ZXJzIjpbeyJkYXRhVHlwZSI6MCwibmFtZSI6IkRldmljZS5EZXZpY2VJbmZvLldlYnBhLlhfQ09NQ0FTVC1DT01fQ0lEIiwidmFsdWUiOiIwIn0seyJkYXRhVHlwZSI6MiwibmFtZSI6IkRldmljZS5EZXZpY2VJbmZvLldlYnBhLlhfQ09NQ0FTVC1DT01fQ01DIiwidmFsdWUiOiIyNjkifV19",
		expected: Payload{
			"parameters": []Payload{
				Payload{
					"name":     "Device.DeviceInfo.Webpa.X_COMCAST-COM_CID",
					"value":    "0",
					"dataType": 0,
				},
				Payload{
					"name":     "Device.DeviceInfo.Webpa.X_COMCAST-COM_CMC",
					"value":    "269",
					"dataType": 2,
				},
			},
		},
	},
}

func TestDecodeBase64(t *testing.T) {
	assertions := assert.New(t)
	for _, record := range payloadTestData {
		var actual Payload
		if err := actual.DecodeBase64(record.encoding, record.value); err != nil {
			t.Errorf("DecodeBase64 failed: %v", err)
		}

		expectedJson, err := json.Marshal(record.expected)
		if err != nil {
			t.Fatalf("Unable to marshal expected JSON: %v", err)
		}

		actualJson, err := json.Marshal(actual)
		if err != nil {
			t.Fatalf("Unable to marshal actual JSON: %v", err)
		}

		assertions.JSONEq(string(expectedJson), string(actualJson))
	}
}

func TestEncodeBase64(t *testing.T) {
	assertions := assert.New(t)
	for _, record := range payloadTestData {
		// perform the reverse test: use the expected as our actual JSON
		actualEncoded, err := record.expected.EncodeBase64(record.encoding)
		if err != nil {
			t.Fatalf("Unable to encode: %v", err)
		}

		// decode the actual value, to get JSON that was can compare against
		actualInput := bytes.NewBufferString(actualEncoded)
		actualDecoder := base64.NewDecoder(record.encoding, actualInput)
		actualJson, err := ioutil.ReadAll(actualDecoder)
		if err != nil {
			t.Fatalf("Unable to decode the output of EncodeBase64: %v", err)
		}

		expectedInput := bytes.NewBufferString(record.value)
		expectedDecoder := base64.NewDecoder(record.encoding, expectedInput)
		expectedJson, err := ioutil.ReadAll(expectedDecoder)
		if err != nil {
			t.Fatalf("Unable to decode expected value: %v", err)
		}

		assertions.JSONEq(string(expectedJson), string(actualJson))
	}
}

func TestParsePayload(t *testing.T) {
	assertions := assert.New(t)
	for _, record := range payloadTestData {
		actualPayload, err := ParsePayload(record.encoding, record.value)
		if err != nil {
			t.Fatalf("ParsePayload failed: %v", err)
		}

		actualJson, err := json.Marshal(actualPayload)
		if err != nil {
			t.Fatalf("Failed to marshal actual payload: %v", err)
		}

		expectedJson, err := json.Marshal(record.expected)
		if err != nil {
			t.Fatalf("Failed to marshal expected JSON: %v", err)
		}

		assertions.JSONEq(string(expectedJson), string(actualJson))
	}
}
<commit_msg>Updated generation URL<commit_after>package convey

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"github.com/stretchr/testify/assert"
	"io/ioutil"
	"testing"
)

// payloadTestData can be generated with:
// https://play.golang.org/p/T0ymv6RE4l
var payloadTestData = []struct {
	encoding *base64.Encoding
	value    string
	expected Payload
}{
	{
		encoding: base64.StdEncoding,
		value:    "eyAicGFyYW1ldGVycyI6IFsgeyAibmFtZSI6ICJEZXZpY2UuRGV2aWNlSW5mby5XZWJwYS5YX0NPTUNBU1QtQ09NX0NJRCIsICJ2YWx1ZSI6ICIwIiwgImRhdGFUeXBlIjogMCB9LCB7ICJuYW1lIjogIkRldmljZS5EZXZpY2VJbmZvLldlYnBhLlhfQ09NQ0FTVC1DT01fQ01DIiwgInZhbHVlIjogIjI2OSIsICJkYXRhVHlwZSI6IDIgfSBdIH0K",
		expected: Payload{
			"parameters": []Payload{
				Payload{
					"name":     "Device.DeviceInfo.Webpa.X_COMCAST-COM_CID",
					"value":    "0",
					"dataType": 0,
				},
				Payload{
					"name":     "Device.DeviceInfo.Webpa.X_COMCAST-COM_CMC",
					"value":    "269",
					"dataType": 2,
				},
			},
		},
	},
	{
		encoding: base64.RawURLEncoding,
		value:    "eyJwYXJhbWV0ZXJzIjpbeyJkYXRhVHlwZSI6MCwibmFtZSI6IkRldmljZS5EZXZpY2VJbmZvLldlYnBhLlhfQ09NQ0FTVC1DT01fQ0lEIiwidmFsdWUiOiIwIn0seyJkYXRhVHlwZSI6MiwibmFtZSI6IkRldmljZS5EZXZpY2VJbmZvLldlYnBhLlhfQ09NQ0FTVC1DT01fQ01DIiwidmFsdWUiOiIyNjkifV19",
		expected: Payload{
			"parameters": []Payload{
				Payload{
					"name":     "Device.DeviceInfo.Webpa.X_COMCAST-COM_CID",
					"value":    "0",
					"dataType": 0,
				},
				Payload{
					"name":     "Device.DeviceInfo.Webpa.X_COMCAST-COM_CMC",
					"value":    "269",
					"dataType": 2,
				},
			},
		},
	},
	{
		encoding: base64.URLEncoding,
		value:    "eyJwYXJhbWV0ZXJzIjpbeyJkYXRhVHlwZSI6MCwibmFtZSI6IkRldmljZS5EZXZpY2VJbmZvLldlYnBhLlhfQ09NQ0FTVC1DT01fQ0lEIiwidmFsdWUiOiIwIn0seyJkYXRhVHlwZSI6MiwibmFtZSI6IkRldmljZS5EZXZpY2VJbmZvLldlYnBhLlhfQ09NQ0FTVC1DT01fQ01DIiwidmFsdWUiOiIyNjkifV19",
		expected: Payload{
			"parameters": []Payload{
				Payload{
					"name":     "Device.DeviceInfo.Webpa.X_COMCAST-COM_CID",
					"value":    "0",
					"dataType": 0,
				},
				Payload{
					"name":     "Device.DeviceInfo.Webpa.X_COMCAST-COM_CMC",
					"value":    "269",
					"dataType": 2,
				},
			},
		},
	},
	{
		encoding: base64.RawStdEncoding,
		value:    "eyJwYXJhbWV0ZXJzIjpbeyJkYXRhVHlwZSI6MCwibmFtZSI6IkRldmljZS5EZXZpY2VJbmZvLldlYnBhLlhfQ09NQ0FTVC1DT01fQ0lEIiwidmFsdWUiOiIwIn0seyJkYXRhVHlwZSI6MiwibmFtZSI6IkRldmljZS5EZXZpY2VJbmZvLldlYnBhLlhfQ09NQ0FTVC1DT01fQ01DIiwidmFsdWUiOiIyNjkifV19",
		expected: Payload{
			"parameters": []Payload{
				Payload{
					"name":     "Device.DeviceInfo.Webpa.X_COMCAST-COM_CID",
					"value":    "0",
					"dataType": 0,
				},
				Payload{
					"name":     "Device.DeviceInfo.Webpa.X_COMCAST-COM_CMC",
					"value":    "269",
					"dataType": 2,
				},
			},
		},
	},
}

func TestDecodeBase64(t *testing.T) {
	assertions := assert.New(t)
	for _, record := range payloadTestData {
		var actual Payload
		if err := actual.DecodeBase64(record.encoding, record.value); err != nil {
			t.Errorf("DecodeBase64 failed: %v", err)
		}

		expectedJson, err := json.Marshal(record.expected)
		if err != nil {
			t.Fatalf("Unable to marshal expected JSON: %v", err)
		}

		actualJson, err := json.Marshal(actual)
		if err != nil {
			t.Fatalf("Unable to marshal actual JSON: %v", err)
		}

		assertions.JSONEq(string(expectedJson), string(actualJson))
	}
}

func TestEncodeBase64(t *testing.T) {
	assertions := assert.New(t)
	for _, record := range payloadTestData {
		// perform the reverse test: use the expected as our actual JSON
		actualEncoded, err := record.expected.EncodeBase64(record.encoding)
		if err != nil {
			t.Fatalf("Unable to encode: %v", err)
		}

		// decode the actual value, to get JSON that was can compare against
		actualInput := bytes.NewBufferString(actualEncoded)
		actualDecoder := base64.NewDecoder(record.encoding, actualInput)
		actualJson, err := ioutil.ReadAll(actualDecoder)
		if err != nil {
			t.Fatalf("Unable to decode the output of EncodeBase64: %v", err)
		}

		expectedInput := bytes.NewBufferString(record.value)
		expectedDecoder := base64.NewDecoder(record.encoding, expectedInput)
		expectedJson, err := ioutil.ReadAll(expectedDecoder)
		if err != nil {
			t.Fatalf("Unable to decode expected value: %v", err)
		}

		assertions.JSONEq(string(expectedJson), string(actualJson))
	}
}

func TestParsePayload(t *testing.T) {
	assertions := assert.New(t)
	for _, record := range payloadTestData {
		actualPayload, err := ParsePayload(record.encoding, record.value)
		if err != nil {
			t.Fatalf("ParsePayload failed: %v", err)
		}

		actualJson, err := json.Marshal(actualPayload)
		if err != nil {
			t.Fatalf("Failed to marshal actual payload: %v", err)
		}

		expectedJson, err := json.Marshal(record.expected)
		if err != nil {
			t.Fatalf("Failed to marshal expected JSON: %v", err)
		}

		assertions.JSONEq(string(expectedJson), string(actualJson))
	}
}
<|endoftext|>


<commit_before>package socks

import (
	"net"

	"github.com/v2ray/v2ray-core/common/log"
	v2net "github.com/v2ray/v2ray-core/common/net"
	"github.com/v2ray/v2ray-core/proxy/socks/protocol"
)

const (
	bufferSize = 2 * 1024
)

var udpAddress v2net.Address

func (server *SocksServer) ListenUDP(port uint16) error {
	addr := &net.UDPAddr{
		IP:   net.IP{127, 0, 0, 1},
		Port: int(port),
		Zone: "",
	}
	conn, err := net.ListenUDP("udp", addr)
	if err != nil {
		log.Error("Socks failed to listen UDP on port %d: %v", port, err)
		return err
	}
	udpAddress = v2net.IPAddress([]byte{127, 0, 0, 1}, port)

	go server.AcceptPackets(conn)
	return nil
}

func (server *SocksServer) getUDPAddr() v2net.Address {
	return udpAddress
}

func (server *SocksServer) AcceptPackets(conn *net.UDPConn) error {
	for {
		buffer := make([]byte, bufferSize)
		nBytes, addr, err := conn.ReadFromUDP(buffer)
		if err != nil {
			log.Error("Socks failed to read UDP packets: %v", err)
			continue
		}
		request, err := protocol.ReadUDPRequest(buffer[:nBytes])
		if err != nil {
			log.Error("Socks failed to parse UDP request: %v", err)
			continue
		}
		if request.Fragment != 0 {
			// TODO handle fragments
			continue
		}

		udpPacket := v2net.NewPacket(request.Destination(), request.Data, false)
		go server.handlePacket(conn, udpPacket, addr, request)
	}
}

func (server *SocksServer) handlePacket(conn *net.UDPConn, packet v2net.Packet, clientAddr *net.UDPAddr, request protocol.Socks5UDPRequest) {
	ray := server.vPoint.DispatchToOutbound(packet)
	close(ray.InboundInput())

	if data, ok := <-ray.InboundOutput(); ok {
		request.Data = data
		udpMessage := request.Bytes(nil)
		nBytes, err := conn.WriteToUDP(udpMessage, clientAddr)
		if err != nil {
			log.Error("Socks failed to write UDP message (%d bytes) to %s: %v", nBytes, clientAddr.String(), err)
		}
	}
}
<commit_msg>Add warning for fragmented packets<commit_after>package socks

import (
	"net"

	"github.com/v2ray/v2ray-core/common/log"
	v2net "github.com/v2ray/v2ray-core/common/net"
	"github.com/v2ray/v2ray-core/proxy/socks/protocol"
)

const (
	bufferSize = 2 * 1024
)

var udpAddress v2net.Address

func (server *SocksServer) ListenUDP(port uint16) error {
	addr := &net.UDPAddr{
		IP:   net.IP{127, 0, 0, 1},
		Port: int(port),
		Zone: "",
	}
	conn, err := net.ListenUDP("udp", addr)
	if err != nil {
		log.Error("Socks failed to listen UDP on port %d: %v", port, err)
		return err
	}
	udpAddress = v2net.IPAddress([]byte{127, 0, 0, 1}, port)

	go server.AcceptPackets(conn)
	return nil
}

func (server *SocksServer) getUDPAddr() v2net.Address {
	return udpAddress
}

func (server *SocksServer) AcceptPackets(conn *net.UDPConn) error {
	for {
		buffer := make([]byte, bufferSize)
		nBytes, addr, err := conn.ReadFromUDP(buffer)
		if err != nil {
			log.Error("Socks failed to read UDP packets: %v", err)
			continue
		}
		request, err := protocol.ReadUDPRequest(buffer[:nBytes])
		if err != nil {
			log.Error("Socks failed to parse UDP request: %v", err)
			continue
		}
		if request.Fragment != 0 {
			log.Warning("Dropping framented UDP packets.")
			// TODO handle fragments
			continue
		}

		udpPacket := v2net.NewPacket(request.Destination(), request.Data, false)
		go server.handlePacket(conn, udpPacket, addr, request)
	}
}

func (server *SocksServer) handlePacket(conn *net.UDPConn, packet v2net.Packet, clientAddr *net.UDPAddr, request protocol.Socks5UDPRequest) {
	ray := server.vPoint.DispatchToOutbound(packet)
	close(ray.InboundInput())

	if data, ok := <-ray.InboundOutput(); ok {
		request.Data = data
		udpMessage := request.Bytes(nil)
		nBytes, err := conn.WriteToUDP(udpMessage, clientAddr)
		if err != nil {
			log.Error("Socks failed to write UDP message (%d bytes) to %s: %v", nBytes, clientAddr.String(), err)
		}
	}
}
<|endoftext|>