<commit_before>// Copyright (c) 2016 Pani Networks
// 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 cmd

import (
	"encoding/json"
	"fmt"
	"os"
	"strconv"
	"text/tabwriter"

	"github.com/romana/core/common"
	"github.com/romana/core/romana/util"

	cli "github.com/spf13/cobra"
	config "github.com/spf13/viper"
)

// hostCmd represents the host commands
var hostCmd = &cli.Command{
	Use:   "host [add|show|list|remove]",
	Short: "Add, Remove or Show hosts for romana services.",
	Long: `Add, Remove or Show hosts for romana services.

host requires a subcommand, e.g. ` + "`romana host add`." + `

For more information, please check http://romana.io
`,
}

func init() {
	hostCmd.AddCommand(hostAddCmd)
	hostCmd.AddCommand(hostShowCmd)
	hostCmd.AddCommand(hostListCmd)
	hostCmd.AddCommand(hostRemoveCmd)
}

var hostAddCmd = &cli.Command{
	Use:          "add [hostname][hostip][romana cidr][(optional)agent port]",
	Short:        "Add a new host.",
	Long:         `Add a new host.`,
	RunE:         hostAdd,
	SilenceUsage: true,
}

var hostShowCmd = &cli.Command{
	Use:          "show [hostname1][hostname2]...",
	Short:        "Show details for a specific host.",
	Long:         `Show details for a specific host.`,
	RunE:         hostShow,
	SilenceUsage: true,
}

var hostListCmd = &cli.Command{
	Use:          "list",
	Short:        "List all hosts.",
	Long:         `List all hosts.`,
	RunE:         hostList,
	SilenceUsage: true,
}

var hostRemoveCmd = &cli.Command{
	Use:          "remove [hostname|hostip]",
	Short:        "Remove a host.",
	Long:         `Remove a host.`,
	RunE:         hostRemove,
	SilenceUsage: true,
}

func hostAdd(cmd *cli.Command, args []string) error {
	if len(args) < 3 || len(args) > 4 {
		return util.UsageError(cmd,
			fmt.Sprintf("expected 3 or 4 arguments, saw %d: %s", len(args), args))
	}

	hostname := args[0]
	hostip := args[1]
	romanacidr := args[2]
	var agentport int
	if len(args) == 4 {
		var err error
		agentport, err = strconv.Atoi(args[3])
		if err != nil {
			return util.UsageError(cmd,
				fmt.Sprintf("Agent Port number error, saw %s", args[3]))
		}
	} else {
		agentport, _ = strconv.Atoi("9606")
	}

	client, err := common.NewRestClient(common.GetDefaultRestClientConfig(rootURL))
	if err != nil {
		return err
	}

	topologyURL, err := client.GetServiceUrl("topology")
	if err != nil {
		return err
	}

	index := common.IndexResponse{}
	err = client.Get(topologyURL, &index)
	if err != nil {
		return err
	}

	host := common.HostMessage{
		Name:      hostname,
		Ip:        hostip,
		RomanaIp:  romanacidr,
		AgentPort: agentport,
	}
	fmt.Printf("Host (%v) added successfully.\n", host)

	data := common.HostMessage{}
	err = client.Post(topologyURL+"/hosts", host, &data)
	if err != nil {
		fmt.Printf("Error adding host (%s).\n", hostname)
		return err
	}

	fmt.Printf("Host (%s) added successfully.\n", hostname)
	return nil
}

func hostShow(cmd *cli.Command, args []string) error {
	if len(args) < 1 {
		return util.UsageError(cmd,
			fmt.Sprintf("expected at-least 1 argument, saw none"))
	}

	client, err := common.NewRestClient(common.GetDefaultRestClientConfig(rootURL))
	if err != nil {
		return err
	}

	topologyURL, err := client.GetServiceUrl( "topology")
	if err != nil {
		return err
	}

	index := common.IndexResponse{}
	err = client.Get(topologyURL, &index)
	if err != nil {
		return err
	}

	hostURL := index.Links.FindByRel("host-list")
	data := []common.HostMessage{}
	hosts := []common.HostMessage{}
	err = client.Get(hostURL, &data)
	if err != nil {
		return err
	}

	for _, h := range data {
		for _, n := range args {
			if h.Name == n {
				hosts = append(hosts, h)
			}
		}
	}

	if config.GetString("Format") == "json" {
		body, err := json.MarshalIndent(hosts, "", "\t")
		if err != nil {
			return err
		}
		fmt.Println(string(body))
	} else {
		w := new(tabwriter.Writer)
		w.Init(os.Stdout, 0, 8, 0, '\t', 0)
		fmt.Println("Host List")
		fmt.Fprintln(w, "Id\t",
			"Host Name\t",
			"Host IP\t",
			"Romana CIDR\t",
			"Agent Port\t")
		for _, host := range hosts {
			fmt.Fprintln(w, host.Id, "\t",
				host.Name, "\t",
				host.Ip, "\t",
				host.RomanaIp, "\t",
				host.AgentPort, "\t")
		}
		w.Flush()
	}

	return nil
}

func hostList(cmd *cli.Command, args []string) error {
	client, err := common.NewRestClient(common.GetDefaultRestClientConfig(rootURL))
	if err != nil {
		return err
	}

	topologyURL, err := client.GetServiceUrl("topology")
	if err != nil {
		return err
	}

	index := common.IndexResponse{}
	err = client.Get(topologyURL, &index)
	if err != nil {
		return err
	}

	hostURL := index.Links.FindByRel("host-list")
	hosts := []common.HostMessage{}
	err = client.Get(hostURL, &hosts)
	if err != nil {
		return err
	}

	if config.GetString("Format") == "json" {
		body, err := json.MarshalIndent(hosts, "", "\t")
		if err != nil {
			return err
		}
		fmt.Println(string(body))
	} else {
		w := new(tabwriter.Writer)
		w.Init(os.Stdout, 0, 8, 0, '\t', 0)
		fmt.Println("Host List")
		fmt.Fprintln(w, "Id\t",
			"Host Name\t",
			"Host IP\t",
			"Romana CIDR\t",
			"Agent Port\t")
		for _, host := range hosts {
			fmt.Fprintln(w, host.Id, "\t",
				host.Name, "\t",
				host.Ip, "\t",
				host.RomanaIp, "\t",
				host.AgentPort, "\t")
		}
		w.Flush()
	}

	return nil
}

func hostRemove(cmd *cli.Command, args []string) error {
	fmt.Println("Unimplemented: Remove a host.")
	return nil
}
<commit_msg>port type<commit_after>// Copyright (c) 2016 Pani Networks
// 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 cmd

import (
	"encoding/json"
	"fmt"
	"os"
	"strconv"
	"text/tabwriter"

	"github.com/romana/core/common"
	"github.com/romana/core/romana/util"

	cli "github.com/spf13/cobra"
	config "github.com/spf13/viper"
)

// hostCmd represents the host commands
var hostCmd = &cli.Command{
	Use:   "host [add|show|list|remove]",
	Short: "Add, Remove or Show hosts for romana services.",
	Long: `Add, Remove or Show hosts for romana services.

host requires a subcommand, e.g. ` + "`romana host add`." + `

For more information, please check http://romana.io
`,
}

func init() {
	hostCmd.AddCommand(hostAddCmd)
	hostCmd.AddCommand(hostShowCmd)
	hostCmd.AddCommand(hostListCmd)
	hostCmd.AddCommand(hostRemoveCmd)
}

var hostAddCmd = &cli.Command{
	Use:          "add [hostname][hostip][romana cidr][(optional)agent port]",
	Short:        "Add a new host.",
	Long:         `Add a new host.`,
	RunE:         hostAdd,
	SilenceUsage: true,
}

var hostShowCmd = &cli.Command{
	Use:          "show [hostname1][hostname2]...",
	Short:        "Show details for a specific host.",
	Long:         `Show details for a specific host.`,
	RunE:         hostShow,
	SilenceUsage: true,
}

var hostListCmd = &cli.Command{
	Use:          "list",
	Short:        "List all hosts.",
	Long:         `List all hosts.`,
	RunE:         hostList,
	SilenceUsage: true,
}

var hostRemoveCmd = &cli.Command{
	Use:          "remove [hostname|hostip]",
	Short:        "Remove a host.",
	Long:         `Remove a host.`,
	RunE:         hostRemove,
	SilenceUsage: true,
}

func hostAdd(cmd *cli.Command, args []string) error {
	if len(args) < 3 || len(args) > 4 {
		return util.UsageError(cmd,
			fmt.Sprintf("expected 3 or 4 arguments, saw %d: %s", len(args), args))
	}

	hostname := args[0]
	hostip := args[1]
	romanacidr := args[2]
	var agentport uint64
	if len(args) == 4 {
		var err error
		agentport, err = strconv.Atoi(args[3])
		if err != nil {
			return util.UsageError(cmd,
				fmt.Sprintf("Agent Port number error, saw %s", args[3]))
		}
	} else {
		agentport, _ = strconv.Atoi("9606")
	}

	client, err := common.NewRestClient(common.GetDefaultRestClientConfig(rootURL))
	if err != nil {
		return err
	}

	topologyURL, err := client.GetServiceUrl("topology")
	if err != nil {
		return err
	}

	index := common.IndexResponse{}
	err = client.Get(topologyURL, &index)
	if err != nil {
		return err
	}

	host := common.HostMessage{
		Name:      hostname,
		Ip:        hostip,
		RomanaIp:  romanacidr,
		AgentPort: agentport,
	}
	fmt.Printf("Host (%v) added successfully.\n", host)

	data := common.HostMessage{}
	err = client.Post(topologyURL+"/hosts", host, &data)
	if err != nil {
		fmt.Printf("Error adding host (%s).\n", hostname)
		return err
	}

	fmt.Printf("Host (%s) added successfully.\n", hostname)
	return nil
}

func hostShow(cmd *cli.Command, args []string) error {
	if len(args) < 1 {
		return util.UsageError(cmd,
			fmt.Sprintf("expected at-least 1 argument, saw none"))
	}

	client, err := common.NewRestClient(common.GetDefaultRestClientConfig(rootURL))
	if err != nil {
		return err
	}

	topologyURL, err := client.GetServiceUrl( "topology")
	if err != nil {
		return err
	}

	index := common.IndexResponse{}
	err = client.Get(topologyURL, &index)
	if err != nil {
		return err
	}

	hostURL := index.Links.FindByRel("host-list")
	data := []common.HostMessage{}
	hosts := []common.HostMessage{}
	err = client.Get(hostURL, &data)
	if err != nil {
		return err
	}

	for _, h := range data {
		for _, n := range args {
			if h.Name == n {
				hosts = append(hosts, h)
			}
		}
	}

	if config.GetString("Format") == "json" {
		body, err := json.MarshalIndent(hosts, "", "\t")
		if err != nil {
			return err
		}
		fmt.Println(string(body))
	} else {
		w := new(tabwriter.Writer)
		w.Init(os.Stdout, 0, 8, 0, '\t', 0)
		fmt.Println("Host List")
		fmt.Fprintln(w, "Id\t",
			"Host Name\t",
			"Host IP\t",
			"Romana CIDR\t",
			"Agent Port\t")
		for _, host := range hosts {
			fmt.Fprintln(w, host.Id, "\t",
				host.Name, "\t",
				host.Ip, "\t",
				host.RomanaIp, "\t",
				host.AgentPort, "\t")
		}
		w.Flush()
	}

	return nil
}

func hostList(cmd *cli.Command, args []string) error {
	client, err := common.NewRestClient(common.GetDefaultRestClientConfig(rootURL))
	if err != nil {
		return err
	}

	topologyURL, err := client.GetServiceUrl("topology")
	if err != nil {
		return err
	}

	index := common.IndexResponse{}
	err = client.Get(topologyURL, &index)
	if err != nil {
		return err
	}

	hostURL := index.Links.FindByRel("host-list")
	hosts := []common.HostMessage{}
	err = client.Get(hostURL, &hosts)
	if err != nil {
		return err
	}

	if config.GetString("Format") == "json" {
		body, err := json.MarshalIndent(hosts, "", "\t")
		if err != nil {
			return err
		}
		fmt.Println(string(body))
	} else {
		w := new(tabwriter.Writer)
		w.Init(os.Stdout, 0, 8, 0, '\t', 0)
		fmt.Println("Host List")
		fmt.Fprintln(w, "Id\t",
			"Host Name\t",
			"Host IP\t",
			"Romana CIDR\t",
			"Agent Port\t")
		for _, host := range hosts {
			fmt.Fprintln(w, host.Id, "\t",
				host.Name, "\t",
				host.Ip, "\t",
				host.RomanaIp, "\t",
				host.AgentPort, "\t")
		}
		w.Flush()
	}

	return nil
}

func hostRemove(cmd *cli.Command, args []string) error {
	fmt.Println("Unimplemented: Remove a host.")
	return nil
}
<|endoftext|>


<commit_before>package docker

import (
	"bufio"
	"fmt"
	"github.com/dotcloud/docker/rcli"
	"io"
	"io/ioutil"
	"strings"
	"testing"
	"time"
)

func closeWrap(args ...io.Closer) error {
	e := false
	ret := fmt.Errorf("Error closing elements")
	for _, c := range args {
		if err := c.Close(); err != nil {
			e = true
			ret = fmt.Errorf("%s\n%s", ret, err)
		}
	}
	if e {
		return ret
	}
	return nil
}

func setTimeout(t *testing.T, msg string, d time.Duration, f func()) {
	c := make(chan bool)

	// Make sure we are not too long
	go func() {
		time.Sleep(d)
		c <- true
	}()
	go func() {
		f()
		c <- false
	}()
	if <-c {
		t.Fatal(msg)
	}
}

func assertPipe(input, output string, r io.Reader, w io.Writer, count int) error {
	for i := 0; i < count; i++ {
		if _, err := w.Write([]byte(input)); err != nil {
			return err
		}
		o, err := bufio.NewReader(r).ReadString('\n')
		if err != nil {
			return err
		}
		if strings.Trim(o, " \r\n") != output {
			return fmt.Errorf("Unexpected output. Expected [%s], received [%s]", output, o)
		}
	}
	return nil
}

// TestRunHostname checks that 'docker run -h' correctly sets a custom hostname
func TestRunHostname(t *testing.T) {
	runtime, err := newTestRuntime()
	if err != nil {
		t.Fatal(err)
	}
	defer nuke(runtime)

	srv := &Server{runtime: runtime}

	stdin, _ := io.Pipe()
	stdout, stdoutPipe := io.Pipe()

	c := make(chan struct{})
	go func() {
		if err := srv.CmdRun(stdin, rcli.NewDockerLocalConn(stdoutPipe), "-h", "foobar", GetTestImage(runtime).Id, "hostname"); err != nil {
			t.Fatal(err)
		}
		close(c)
	}()
	cmdOutput, err := bufio.NewReader(stdout).ReadString('\n')
	if err != nil {
		t.Fatal(err)
	}
	if cmdOutput != "foobar\n" {
		t.Fatalf("'hostname' should display '%s', not '%s'", "foobar\n", cmdOutput)
	}

	setTimeout(t, "CmdRun timed out", 2*time.Second, func() {
		<-c
	})
}

func TestRunExit(t *testing.T) {
	runtime, err := newTestRuntime()
	if err != nil {
		t.Fatal(err)
	}
	defer nuke(runtime)

	srv := &Server{runtime: runtime}

	stdin, stdinPipe := io.Pipe()
	stdout, stdoutPipe := io.Pipe()
	c1 := make(chan struct{})
	go func() {
		srv.CmdRun(stdin, stdoutPipe, "-i", GetTestImage(runtime).Id, "/bin/cat")
		close(c1)
	}()

	setTimeout(t, "Read/Write assertion timed out", 2*time.Second, func() {
		if err := assertPipe("hello\n", "hello", stdout, stdinPipe, 15); err != nil {
			t.Fatal(err)
		}
	})

	container := runtime.List()[0]

	// Closing /bin/cat stdin, expect it to exit
	p, err := container.StdinPipe()
	if err != nil {
		t.Fatal(err)
	}
	if err := p.Close(); err != nil {
		t.Fatal(err)
	}

	// as the process exited, CmdRun must finish and unblock. Wait for it
	setTimeout(t, "Waiting for CmdRun timed out", 2*time.Second, func() {
		<-c1
	})

	// Make sure that the client has been disconnected
	setTimeout(t, "The client should have been disconnected once the remote process exited.", 2*time.Second, func() {
		// Expecting pipe i/o error, just check that read does not block
		stdin.Read([]byte{})
	})

	// Cleanup pipes
	if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
		t.Fatal(err)
	}
}

// Expected behaviour: the process dies when the client disconnects
func TestRunDisconnect(t *testing.T) {
	runtime, err := newTestRuntime()
	if err != nil {
		t.Fatal(err)
	}
	defer nuke(runtime)

	srv := &Server{runtime: runtime}

	stdin, stdinPipe := io.Pipe()
	stdout, stdoutPipe := io.Pipe()
	c1 := make(chan struct{})
	go func() {
		// We're simulating a disconnect so the return value doesn't matter. What matters is the
		// fact that CmdRun returns.
		srv.CmdRun(stdin, rcli.NewDockerLocalConn(stdoutPipe), "-i", GetTestImage(runtime).Id, "/bin/cat")
		close(c1)
	}()

	setTimeout(t, "Read/Write assertion timed out", 2*time.Second, func() {
		if err := assertPipe("hello\n", "hello", stdout, stdinPipe, 15); err != nil {
			t.Fatal(err)
		}
	})

	// Close pipes (simulate disconnect)
	if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
		t.Fatal(err)
	}

	// as the pipes are close, we expect the process to die,
	// therefore CmdRun to unblock. Wait for CmdRun
	setTimeout(t, "Waiting for CmdRun timed out", 2*time.Second, func() {
		<-c1
	})

	// Client disconnect after run -i should cause stdin to be closed, which should
	// cause /bin/cat to exit.
	setTimeout(t, "Waiting for /bin/cat to exit timed out", 2*time.Second, func() {
		container := runtime.List()[0]
		container.Wait()
		if container.State.Running {
			t.Fatalf("/bin/cat is still running after closing stdin")
		}
	})
}

// TestAttachStdin checks attaching to stdin without stdout and stderr.
// 'docker run -i -a stdin' should sends the client's stdin to the command,
// then detach from it and print the container id.
func TestRunAttachStdin(t *testing.T) {
	runtime, err := newTestRuntime()
	if err != nil {
		t.Fatal(err)
	}
	defer nuke(runtime)
	srv := &Server{runtime: runtime}

	stdin, stdinPipe := io.Pipe()
	stdout, stdoutPipe := io.Pipe()

	ch := make(chan struct{})
	go func() {
		srv.CmdRun(stdin, rcli.NewDockerLocalConn(stdoutPipe), "-i", "-a", "stdin", GetTestImage(runtime).Id, "sh", "-c", "echo hello; cat")
		close(ch)
	}()

	// Send input to the command, close stdin
	setTimeout(t, "Write timed out", 2*time.Second, func() {
		if _, err := stdinPipe.Write([]byte("hi there\n")); err != nil {
			t.Fatal(err)
		}
		if err := stdinPipe.Close(); err != nil {
			t.Fatal(err)
		}
	})

	container := runtime.List()[0]

	// Check output
	cmdOutput, err := bufio.NewReader(stdout).ReadString('\n')
	if err != nil {
		t.Fatal(err)
	}
	if cmdOutput != container.ShortId()+"\n" {
		t.Fatalf("Wrong output: should be '%s', not '%s'\n", container.ShortId()+"\n", cmdOutput)
	}

	// wait for CmdRun to return
	setTimeout(t, "Waiting for CmdRun timed out", 2*time.Second, func() {
		<-ch
	})

	setTimeout(t, "Waiting for command to exit timed out", 2*time.Second, func() {
		container.Wait()
	})

	// Check logs
	if cmdLogs, err := container.ReadLog("stdout"); err != nil {
		t.Fatal(err)
	} else {
		if output, err := ioutil.ReadAll(cmdLogs); err != nil {
			t.Fatal(err)
		} else {
			expectedLog := "hello\nhi there\n"
			if string(output) != expectedLog {
				t.Fatalf("Unexpected logs: should be '%s', not '%s'\n", expectedLog, output)
			}
		}
	}
}

// Expected behaviour, the process stays alive when the client disconnects
func TestAttachDisconnect(t *testing.T) {
	runtime, err := newTestRuntime()
	if err != nil {
		t.Fatal(err)
	}
	defer nuke(runtime)

	srv := &Server{runtime: runtime}

	container, err := runtime.Create(
		&Config{
			Image:     GetTestImage(runtime).Id,
			Memory:    33554432,
			Cmd:       []string{"/bin/cat"},
			OpenStdin: true,
		},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer runtime.Destroy(container)

	// Start the process
	if err := container.Start(); err != nil {
		t.Fatal(err)
	}

	stdin, stdinPipe := io.Pipe()
	stdout, stdoutPipe := io.Pipe()

	// Attach to it
	c1 := make(chan struct{})
	go func() {
		// We're simulating a disconnect so the return value doesn't matter. What matters is the
		// fact that CmdAttach returns.
		srv.CmdAttach(stdin, rcli.NewDockerLocalConn(stdoutPipe), container.Id)
		close(c1)
	}()

	setTimeout(t, "First read/write assertion timed out", 2*time.Second, func() {
		if err := assertPipe("hello\n", "hello", stdout, stdinPipe, 15); err != nil {
			t.Fatal(err)
		}
	})
	// Close pipes (client disconnects)
	if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
		t.Fatal(err)
	}

	// Wait for attach to finish, the client disconnected, therefore, Attach finished his job
	setTimeout(t, "Waiting for CmdAttach timed out", 2*time.Second, func() {
		<-c1
	})

	// We closed stdin, expect /bin/cat to still be running
	// Wait a little bit to make sure container.monitor() did his thing
	err = container.WaitTimeout(500 * time.Millisecond)
	if err == nil || !container.State.Running {
		t.Fatalf("/bin/cat is not running after closing stdin")
	}

	// Try to avoid the timeoout in destroy. Best effort, don't check error
	cStdin, _ := container.StdinPipe()
	cStdin.Close()
}
<commit_msg>Update the tests according to the "optional raw mode" changes<commit_after>package docker

import (
	"bufio"
	"fmt"
	"github.com/dotcloud/docker/rcli"
	"io"
	"io/ioutil"
	"strings"
	"testing"
	"time"
)

func closeWrap(args ...io.Closer) error {
	e := false
	ret := fmt.Errorf("Error closing elements")
	for _, c := range args {
		if err := c.Close(); err != nil {
			e = true
			ret = fmt.Errorf("%s\n%s", ret, err)
		}
	}
	if e {
		return ret
	}
	return nil
}

func setTimeout(t *testing.T, msg string, d time.Duration, f func()) {
	c := make(chan bool)

	// Make sure we are not too long
	go func() {
		time.Sleep(d)
		c <- true
	}()
	go func() {
		f()
		c <- false
	}()
	if <-c {
		t.Fatal(msg)
	}
}

func assertPipe(input, output string, r io.Reader, w io.Writer, count int) error {
	for i := 0; i < count; i++ {
		if _, err := w.Write([]byte(input)); err != nil {
			return err
		}
		o, err := bufio.NewReader(r).ReadString('\n')
		if err != nil {
			return err
		}
		if strings.Trim(o, " \r\n") != output {
			return fmt.Errorf("Unexpected output. Expected [%s], received [%s]", output, o)
		}
	}
	return nil
}

// TestRunHostname checks that 'docker run -h' correctly sets a custom hostname
func TestRunHostname(t *testing.T) {
	runtime, err := newTestRuntime()
	if err != nil {
		t.Fatal(err)
	}
	defer nuke(runtime)

	srv := &Server{runtime: runtime}

	stdin, _ := io.Pipe()
	stdout, stdoutPipe := io.Pipe()

	c := make(chan struct{})
	go func() {
		if err := srv.CmdRun(stdin, rcli.NewDockerLocalConn(stdoutPipe), "-h", "foobar", GetTestImage(runtime).Id, "hostname"); err != nil {
			t.Fatal(err)
		}
		close(c)
	}()
	cmdOutput, err := bufio.NewReader(stdout).ReadString('\n')
	if err != nil {
		t.Fatal(err)
	}
	if cmdOutput != "foobar\n" {
		t.Fatalf("'hostname' should display '%s', not '%s'", "foobar\n", cmdOutput)
	}

	setTimeout(t, "CmdRun timed out", 2*time.Second, func() {
		<-c
	})
}

func TestRunExit(t *testing.T) {
	runtime, err := newTestRuntime()
	if err != nil {
		t.Fatal(err)
	}
	defer nuke(runtime)

	srv := &Server{runtime: runtime}

	stdin, stdinPipe := io.Pipe()
	stdout, stdoutPipe := io.Pipe()
	c1 := make(chan struct{})
	go func() {
		srv.CmdRun(stdin, rcli.NewDockerLocalConn(stdoutPipe), "-i", GetTestImage(runtime).Id, "/bin/cat")
		close(c1)
	}()

	setTimeout(t, "Read/Write assertion timed out", 2*time.Second, func() {
		if err := assertPipe("hello\n", "hello", stdout, stdinPipe, 15); err != nil {
			t.Fatal(err)
		}
	})

	container := runtime.List()[0]

	// Closing /bin/cat stdin, expect it to exit
	p, err := container.StdinPipe()
	if err != nil {
		t.Fatal(err)
	}
	if err := p.Close(); err != nil {
		t.Fatal(err)
	}

	// as the process exited, CmdRun must finish and unblock. Wait for it
	setTimeout(t, "Waiting for CmdRun timed out", 2*time.Second, func() {
		<-c1
	})

	// Make sure that the client has been disconnected
	setTimeout(t, "The client should have been disconnected once the remote process exited.", 2*time.Second, func() {
		// Expecting pipe i/o error, just check that read does not block
		stdin.Read([]byte{})
	})

	// Cleanup pipes
	if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
		t.Fatal(err)
	}
}

// Expected behaviour: the process dies when the client disconnects
func TestRunDisconnect(t *testing.T) {
	runtime, err := newTestRuntime()
	if err != nil {
		t.Fatal(err)
	}
	defer nuke(runtime)

	srv := &Server{runtime: runtime}

	stdin, stdinPipe := io.Pipe()
	stdout, stdoutPipe := io.Pipe()
	c1 := make(chan struct{})
	go func() {
		// We're simulating a disconnect so the return value doesn't matter. What matters is the
		// fact that CmdRun returns.
		srv.CmdRun(stdin, rcli.NewDockerLocalConn(stdoutPipe), "-i", GetTestImage(runtime).Id, "/bin/cat")
		close(c1)
	}()

	setTimeout(t, "Read/Write assertion timed out", 2*time.Second, func() {
		if err := assertPipe("hello\n", "hello", stdout, stdinPipe, 15); err != nil {
			t.Fatal(err)
		}
	})

	// Close pipes (simulate disconnect)
	if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
		t.Fatal(err)
	}

	// as the pipes are close, we expect the process to die,
	// therefore CmdRun to unblock. Wait for CmdRun
	setTimeout(t, "Waiting for CmdRun timed out", 2*time.Second, func() {
		<-c1
	})

	// Client disconnect after run -i should cause stdin to be closed, which should
	// cause /bin/cat to exit.
	setTimeout(t, "Waiting for /bin/cat to exit timed out", 2*time.Second, func() {
		container := runtime.List()[0]
		container.Wait()
		if container.State.Running {
			t.Fatalf("/bin/cat is still running after closing stdin")
		}
	})
}

// TestAttachStdin checks attaching to stdin without stdout and stderr.
// 'docker run -i -a stdin' should sends the client's stdin to the command,
// then detach from it and print the container id.
func TestRunAttachStdin(t *testing.T) {
	runtime, err := newTestRuntime()
	if err != nil {
		t.Fatal(err)
	}
	defer nuke(runtime)
	srv := &Server{runtime: runtime}

	stdin, stdinPipe := io.Pipe()
	stdout, stdoutPipe := io.Pipe()

	ch := make(chan struct{})
	go func() {
		srv.CmdRun(stdin, rcli.NewDockerLocalConn(stdoutPipe), "-i", "-a", "stdin", GetTestImage(runtime).Id, "sh", "-c", "echo hello; cat")
		close(ch)
	}()

	// Send input to the command, close stdin
	setTimeout(t, "Write timed out", 2*time.Second, func() {
		if _, err := stdinPipe.Write([]byte("hi there\n")); err != nil {
			t.Fatal(err)
		}
		if err := stdinPipe.Close(); err != nil {
			t.Fatal(err)
		}
	})

	container := runtime.List()[0]

	// Check output
	cmdOutput, err := bufio.NewReader(stdout).ReadString('\n')
	if err != nil {
		t.Fatal(err)
	}
	if cmdOutput != container.ShortId()+"\n" {
		t.Fatalf("Wrong output: should be '%s', not '%s'\n", container.ShortId()+"\n", cmdOutput)
	}

	// wait for CmdRun to return
	setTimeout(t, "Waiting for CmdRun timed out", 2*time.Second, func() {
		<-ch
	})

	setTimeout(t, "Waiting for command to exit timed out", 2*time.Second, func() {
		container.Wait()
	})

	// Check logs
	if cmdLogs, err := container.ReadLog("stdout"); err != nil {
		t.Fatal(err)
	} else {
		if output, err := ioutil.ReadAll(cmdLogs); err != nil {
			t.Fatal(err)
		} else {
			expectedLog := "hello\nhi there\n"
			if string(output) != expectedLog {
				t.Fatalf("Unexpected logs: should be '%s', not '%s'\n", expectedLog, output)
			}
		}
	}
}

// Expected behaviour, the process stays alive when the client disconnects
func TestAttachDisconnect(t *testing.T) {
	runtime, err := newTestRuntime()
	if err != nil {
		t.Fatal(err)
	}
	defer nuke(runtime)

	srv := &Server{runtime: runtime}

	container, err := runtime.Create(
		&Config{
			Image:     GetTestImage(runtime).Id,
			Memory:    33554432,
			Cmd:       []string{"/bin/cat"},
			OpenStdin: true,
		},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer runtime.Destroy(container)

	// Start the process
	if err := container.Start(); err != nil {
		t.Fatal(err)
	}

	stdin, stdinPipe := io.Pipe()
	stdout, stdoutPipe := io.Pipe()

	// Attach to it
	c1 := make(chan struct{})
	go func() {
		// We're simulating a disconnect so the return value doesn't matter. What matters is the
		// fact that CmdAttach returns.
		srv.CmdAttach(stdin, rcli.NewDockerLocalConn(stdoutPipe), container.Id)
		close(c1)
	}()

	setTimeout(t, "First read/write assertion timed out", 2*time.Second, func() {
		if err := assertPipe("hello\n", "hello", stdout, stdinPipe, 15); err != nil {
			t.Fatal(err)
		}
	})
	// Close pipes (client disconnects)
	if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
		t.Fatal(err)
	}

	// Wait for attach to finish, the client disconnected, therefore, Attach finished his job
	setTimeout(t, "Waiting for CmdAttach timed out", 2*time.Second, func() {
		<-c1
	})

	// We closed stdin, expect /bin/cat to still be running
	// Wait a little bit to make sure container.monitor() did his thing
	err = container.WaitTimeout(500 * time.Millisecond)
	if err == nil || !container.State.Running {
		t.Fatalf("/bin/cat is not running after closing stdin")
	}

	// Try to avoid the timeoout in destroy. Best effort, don't check error
	cStdin, _ := container.StdinPipe()
	cStdin.Close()
}
<|endoftext|>


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

package tls

import "strconv"

type alert uint8

const (
	// alert level
	alertLevelWarning = 1
	alertLevelError   = 2
)

const (
	alertCloseNotify            alert = 0
	alertUnexpectedMessage      alert = 10
	alertBadRecordMAC           alert = 20
	alertDecryptionFailed       alert = 21
	alertRecordOverflow         alert = 22
	alertDecompressionFailure   alert = 30
	alertHandshakeFailure       alert = 40
	alertBadCertificate         alert = 42
	alertUnsupportedCertificate alert = 43
	alertCertificateRevoked     alert = 44
	alertCertificateExpired     alert = 45
	alertCertificateUnknown     alert = 46
	alertIllegalParameter       alert = 47
	alertUnknownCA              alert = 48
	alertAccessDenied           alert = 49
	alertDecodeError            alert = 50
	alertDecryptError           alert = 51
	alertProtocolVersion        alert = 70
	alertInsufficientSecurity   alert = 71
	alertInternalError          alert = 80
	alertUserCanceled           alert = 90
	alertNoRenegotiation        alert = 100
)

var alertText = map[alert]string{
	alertCloseNotify:            "close notify",
	alertUnexpectedMessage:      "unexpected message",
	alertBadRecordMAC:           "bad record MAC",
	alertDecryptionFailed:       "decryption failed",
	alertRecordOverflow:         "record overflow",
	alertDecompressionFailure:   "decompression failure",
	alertHandshakeFailure:       "handshake failure",
	alertBadCertificate:         "bad certificate",
	alertUnsupportedCertificate: "unsupported certificate",
	alertCertificateRevoked:     "revoked certificate",
	alertCertificateExpired:     "expired certificate",
	alertCertificateUnknown:     "unknown certificate",
	alertIllegalParameter:       "illegal parameter",
	alertUnknownCA:              "unknown certificate authority",
	alertAccessDenied:           "access denied",
	alertDecodeError:            "error decoding message",
	alertDecryptError:           "error decrypting message",
	alertProtocolVersion:        "protocol version not supported",
	alertInsufficientSecurity:   "insufficient security level",
	alertInternalError:          "internal error",
	alertUserCanceled:           "user canceled",
	alertNoRenegotiation:        "no renegotiation",
}

func (e alert) String() string {
	s, ok := alertText[e]
	if ok {
		return s
	}
	return "alert(" + strconv.Itoa(int(e)) + ")"
}
<commit_msg>crypto/tls: add Error method to alert<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tls

import "strconv"

type alert uint8

const (
	// alert level
	alertLevelWarning = 1
	alertLevelError   = 2
)

const (
	alertCloseNotify            alert = 0
	alertUnexpectedMessage      alert = 10
	alertBadRecordMAC           alert = 20
	alertDecryptionFailed       alert = 21
	alertRecordOverflow         alert = 22
	alertDecompressionFailure   alert = 30
	alertHandshakeFailure       alert = 40
	alertBadCertificate         alert = 42
	alertUnsupportedCertificate alert = 43
	alertCertificateRevoked     alert = 44
	alertCertificateExpired     alert = 45
	alertCertificateUnknown     alert = 46
	alertIllegalParameter       alert = 47
	alertUnknownCA              alert = 48
	alertAccessDenied           alert = 49
	alertDecodeError            alert = 50
	alertDecryptError           alert = 51
	alertProtocolVersion        alert = 70
	alertInsufficientSecurity   alert = 71
	alertInternalError          alert = 80
	alertUserCanceled           alert = 90
	alertNoRenegotiation        alert = 100
)

var alertText = map[alert]string{
	alertCloseNotify:            "close notify",
	alertUnexpectedMessage:      "unexpected message",
	alertBadRecordMAC:           "bad record MAC",
	alertDecryptionFailed:       "decryption failed",
	alertRecordOverflow:         "record overflow",
	alertDecompressionFailure:   "decompression failure",
	alertHandshakeFailure:       "handshake failure",
	alertBadCertificate:         "bad certificate",
	alertUnsupportedCertificate: "unsupported certificate",
	alertCertificateRevoked:     "revoked certificate",
	alertCertificateExpired:     "expired certificate",
	alertCertificateUnknown:     "unknown certificate",
	alertIllegalParameter:       "illegal parameter",
	alertUnknownCA:              "unknown certificate authority",
	alertAccessDenied:           "access denied",
	alertDecodeError:            "error decoding message",
	alertDecryptError:           "error decrypting message",
	alertProtocolVersion:        "protocol version not supported",
	alertInsufficientSecurity:   "insufficient security level",
	alertInternalError:          "internal error",
	alertUserCanceled:           "user canceled",
	alertNoRenegotiation:        "no renegotiation",
}

func (e alert) String() string {
	s, ok := alertText[e]
	if ok {
		return s
	}
	return "alert(" + strconv.Itoa(int(e)) + ")"
}

func (e alert) Error() string {
	return e.String()
}
<|endoftext|>


<commit_before><commit_msg>client: Update debugging message<commit_after><|endoftext|>


<commit_before>package routers

import (
	"github.com/codegangsta/martini-contrib/render"
	"github.com/go-martini/martini"
)

func Initialize(m *martini.ClassicMartini) {
	m.Use(render.Renderer(render.Options{
		Layout:     "layout",
		Directory:  "templates",
		Extensions: []string{".tpl", ".html"},
		Charset:    "UTF-8",
	}))

	InitRouters(m)
}

func InitRouters(m *martini.ClassicMartini) {
	m.Get("/", HandleIndex)
}
<commit_msg>add DB handler.<commit_after>package routers

import (
	"fmt"
	"github.com/codegangsta/martini-contrib/render"
	"github.com/go-martini/martini"
)

func DB() martini.Handler {
	fmt.Println("DB handler is called...1")

	return func() {
		fmt.Println("DB handler is called...2")
	}
}

func Initialize(m *martini.ClassicMartini) {
	m.Use(render.Renderer(render.Options{
		Layout:     "layout",
		Directory:  "templates",
		Extensions: []string{".tpl", ".html"},
		Charset:    "UTF-8",
	}))

	m.Use(DB)

	InitRouters(m)
}

func InitRouters(m *martini.ClassicMartini) {
	m.Get("/", HandleIndex)
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"github.com/maxtaco/go-framed-msgpack-rpc/rpc2"
	"net"
)

type Server struct {
}

type ArithServer struct {
	c net.Conn
}

func (a *ArithServer) Add(args *AddArgs) (ret int, err error) {
	ret = args.A + args.B
	return
}

func (a *ArithServer) DivMod(args *DivModArgs) (ret *DivModRes, err error) {
	ret = &DivModRes{}
	if args.B == 0 {
		err = errors.New("Cannot divide by 0")
	} else {
		ret.Q = args.A / args.B
		ret.R = args.A % args.B
	}
	return
}

//---------------------------------------------------------------
// begin autogen code

type AddArgs struct {
	A int
	B int
}

type DivModArgs struct {
	A int
	B int
}

type DivModRes struct {
	Q int
	R int
}

type ArithInferface interface {
	Add(*AddArgs) (int, error)
	DivMod(*DivModArgs) (*DivModRes, error)
}

func ArithProtocol(i ArithInferface) rpc2.Protocol {
	return rpc2.Protocol{
		Name: "test.1.arith",
		Methods: map[string]rpc2.ServeHook{
			"add": func(nxt rpc2.DecodeNext) (ret interface{}, err error) {
				var args AddArgs
				if err = nxt(&args); err == nil {
					ret, err = i.Add(&args)
					fmt.Printf("ok returning %v %v\n", ret, err)
				}
				return
			},
			"divMod": func(nxt rpc2.DecodeNext) (ret interface{}, err error) {
				var args DivModArgs
				if err = nxt(&args); err == nil {
					ret, err = i.DivMod(&args)
				}
				return
			},
		},
	}
}

// end autogen code
//---------------------------------------------------------------

func (s *Server) Run() (err error) {
	var listener net.Listener
	fmt.Printf("Listening on port %d...\n", port)
	if listener, err = net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port)); err != nil {
		return
	}
	for {
		var c net.Conn
		if c, err = listener.Accept(); err != nil {
			return
		}
		fmt.Printf("New connection from %v\n", c.RemoteAddr())
		xp := rpc2.NewTransport(c, nil)
		srv := rpc2.NewServer(xp)
		srv.Register(ArithProtocol(&ArithServer{c}))
		srv.Run(true)
	}
	return nil
}
<commit_msg>ok, it's too hot in here<commit_after>package main

import (
	"errors"
	"fmt"
	"github.com/maxtaco/go-framed-msgpack-rpc/rpc2"
	"net"
)

type Server struct {
}

type ArithServer struct {
	c net.Conn
}

func (a *ArithServer) Add(args *AddArgs) (ret int, err error) {
	ret = args.A + args.B
	return
}

func (a *ArithServer) DivMod(args *DivModArgs) (ret *DivModRes, err error) {
	ret = &DivModRes{}
	if args.B == 0 {
		err = errors.New("Cannot divide by 0")
	} else {
		ret.Q = args.A / args.B
		ret.R = args.A % args.B
	}
	return
}

//---------------------------------------------------------------
// begin autogen code

type AddArgs struct {
	A int
	B int
}

type DivModArgs struct {
	A int
	B int
}

type DivModRes struct {
	Q int
	R int
}

type ArithInferface interface {
	Add(*AddArgs) (int, error)
	DivMod(*DivModArgs) (*DivModRes, error)
}

func ArithProtocol(i ArithInferface) rpc2.Protocol {
	return rpc2.Protocol{
		Name: "test.1.arith",
		Methods: map[string]rpc2.ServeHook{
			"add": func(nxt rpc2.DecodeNext) (ret interface{}, err error) {
				var args AddArgs
				if err = nxt(&args); err == nil {
					ret, err = i.Add(&args)
				}
				return
			},
			"divMod": func(nxt rpc2.DecodeNext) (ret interface{}, err error) {
				var args DivModArgs
				if err = nxt(&args); err == nil {
					ret, err = i.DivMod(&args)
				}
				return
			},
		},
	}
}

// end autogen code
//---------------------------------------------------------------

func (s *Server) Run() (err error) {
	var listener net.Listener
	fmt.Printf("Listening on port %d...\n", port)
	if listener, err = net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port)); err != nil {
		return
	}
	for {
		var c net.Conn
		if c, err = listener.Accept(); err != nil {
			return
		}
		fmt.Printf("New connection from %v\n", c.RemoteAddr())
		xp := rpc2.NewTransport(c, nil)
		srv := rpc2.NewServer(xp)
		srv.Register(ArithProtocol(&ArithServer{c}))
		srv.Run(true)
	}
	return nil
}
<|endoftext|>


<commit_before>package main

/*

练习6.4: 实现一个Elems方法，返回集合中的所有元素，用于做一些range之类的遍历操作。

练习 6.5： 我们这章定义的IntSet里的每个字都是用的uint64类型，但是64位的数值可能在32位的平台上不高效。
修改程序，使其使用uint类型，这种类型对于32位平台来说更合适。当然了，这里我们可以不用简单粗暴地除64，
可以定义一个常量来决定是用32还是64，这里你可能会用到平台的自动判断的一个智能表达式：32 << (^uint(0) >> 63)
*/
import (
	"bytes"
	"fmt"
)

var pc []uint64

func init() {
	var i uint64
	pc = make([]uint64, 64, 64)
	for i = 0; i < 64; i++ {
		pc[i] = pc[i/2] + (i % 2)
	}
}

// An IntSet is a set of small non-negative integers.
// Its zero value represents the empty set.
type IntSet struct {
	words []uint64
}

// Has reports whether the set contains the non-negative value x.
func (s *IntSet) Has(x int) bool {
	word, bit := x/64, uint(x%64)
	return word < len(s.words) && s.words[word]&(1<<bit) != 0
}

// Add adds the non-negative value x to the set.
func (s *IntSet) Add(x int) {
	word, bit := x/64, uint(x%64)
	for word >= len(s.words) {
		s.words = append(s.words, 0)
	}
	s.words[word] |= 1 << bit
}

// UnionWith sets s to the union of s and t.
func (s *IntSet) UnionWith(t *IntSet) {
	for i, tword := range t.words {
		if i < len(s.words) {
			s.words[i] |= tword
		} else {
			s.words = append(s.words, tword)
		}
	}
}

// String returns the set as a string of the form "{1 2 3}".
func (s *IntSet) String() string {
	var buf bytes.Buffer
	buf.WriteByte('{')
	for i, word := range s.words {
		if word == 0 {
			continue
		}
		for j := 0; j < 64; j++ {
			if word&(1<<uint(j)) != 0 {
				if buf.Len() > len("{") {
					buf.WriteByte(' ')
				}
				fmt.Fprintf(&buf, "%d", 64*i+j)
			}
		}
	}
	buf.WriteByte('}')
	return buf.String()
}

/*
练习6.1: 为bit数组实现下面这些方法

func (*IntSet) Len() int      // return the number of elements
func (*IntSet) Remove(x int)  // remove x from the set
func (*IntSet) Clear()        // remove all elements from the set
func (*IntSet) Copy() *IntSet // return a copy of the set
*/
func (s *IntSet) Len() int { // return the number of elements
	count := 0
	for _, x := range s.words {
		//fmt.Println(word)
		c := int(pc[byte(x>>(0*8))] +
			pc[byte(x>>(1*8))] +
			pc[byte(x>>(2*8))] +
			pc[byte(x>>(3*8))] +
			pc[byte(x>>(4*8))] +
			pc[byte(x>>(5*8))] +
			pc[byte(x>>(6*8))] +
			pc[byte(x>>(7*8))])
		count += c
	}
	return count
}

func (s *IntSet) Remove(x int) { // remove x from the set
	if s.Has(x) {
		word, bit := x/64, uint(x%64)
		s.words[word] ^= 1 << bit
	}

}

func (s *IntSet) Clear() { // remove all elements from the set
	for k := range s.words {
		s.words[k] = 0
	}
}

func (s *IntSet) Copy() *IntSet { // return a copy of the set
	var res IntSet
	for _, v := range s.words {
		res.words = append(res.words, v)
	}
	return &res
}

/*
练习 6.2：
定义一个变参方法(*IntSet).AddAll(...int)，这个方法可以为一组IntSet值求和(翻译问题吧?)，比如s.AddAll(1,2,3)。
*/

func (s *IntSet)AddAll(nums ...int) {
	for _, n := range nums {
		s.Add(n)
	}
}

/*
练习 6.3：
(*IntSet).UnionWith会用|操作符计算两个集合的并集，
我们再为IntSet实现另外的几个函数
IntersectWith(交集：元素在A集合B集合均出现),  A & B
DifferenceWith(差集：元素出现在A集合，未出现在B集合), A - B = A ^ (A & B)
SymmetricDifference(并差集：元素出现在A但没有出现在B，或者出现在B没有出现在A)。
*/

func (s *IntSet) IntersectWith(t *IntSet) {
	l := len(t.words)
	for i,_ := range s.words {
		if i < l {
			s.words[i] = s.words[i] & t.words[i]
		} else {
			s.words[i] = 0
		}
	}
}

func (s *IntSet) DifferenceWith(t *IntSet) {
	l := len(t.words)
	for i,_ := range s.words {
		if i < l {
			s.words[i] = s.words[i] ^ (s.words[i] & t.words[i])
		}
	}
}

func (s *IntSet) SymmetricDifference(t *IntSet) {

}

func main() {
	var x, y IntSet
	var z *IntSet

	x.Add(64)
	x.Add(2)
	z = x.Copy()
	fmt.Println(x.String())
	fmt.Println("---------")
	y.Add(9)
	y.Add(42)
	fmt.Println(y.String())
	fmt.Println("---------")
	x.UnionWith(&y)
	fmt.Println(x.String())
	x.Clear()
	x.Remove(64)
	x.Remove(1)
	fmt.Println(x.String())
	fmt.Println(z.String())
	fmt.Println(x.Has(9), x.Has(123))

	fmt.Println(x.Len())
	y.AddAll(1,1,2,3,5,8,13,21, 2112)
	fmt.Println(z.String())
	y.IntersectWith(z)
	fmt.Print(y.String())

	y.DifferenceWith(z)
	fmt.Print(y.String())
}
<commit_msg>SymmetricDifference<commit_after>package main

/*

练习6.4: 实现一个Elems方法，返回集合中的所有元素，用于做一些range之类的遍历操作。

练习 6.5： 我们这章定义的IntSet里的每个字都是用的uint64类型，但是64位的数值可能在32位的平台上不高效。
修改程序，使其使用uint类型，这种类型对于32位平台来说更合适。当然了，这里我们可以不用简单粗暴地除64，
可以定义一个常量来决定是用32还是64，这里你可能会用到平台的自动判断的一个智能表达式：32 << (^uint(0) >> 63)
*/
import (
	"bytes"
	"fmt"
)

var pc []uint64

func init() {
	var i uint64
	pc = make([]uint64, 64, 64)
	for i = 0; i < 64; i++ {
		pc[i] = pc[i/2] + (i % 2)
	}
}

// An IntSet is a set of small non-negative integers.
// Its zero value represents the empty set.
type IntSet struct {
	words []uint64
}

// Has reports whether the set contains the non-negative value x.
func (s *IntSet) Has(x int) bool {
	word, bit := x/64, uint(x%64)
	return word < len(s.words) && s.words[word]&(1<<bit) != 0
}

// Add adds the non-negative value x to the set.
func (s *IntSet) Add(x int) {
	word, bit := x/64, uint(x%64)
	for word >= len(s.words) {
		s.words = append(s.words, 0)
	}
	s.words[word] |= 1 << bit
}

// UnionWith sets s to the union of s and t.
func (s *IntSet) UnionWith(t *IntSet) {
	for i, tword := range t.words {
		if i < len(s.words) {
			s.words[i] |= tword
		} else {
			s.words = append(s.words, tword)
		}
	}
}

// String returns the set as a string of the form "{1 2 3}".
func (s *IntSet) String() string {
	var buf bytes.Buffer
	buf.WriteByte('{')
	for i, word := range s.words {
		if word == 0 {
			continue
		}
		for j := 0; j < 64; j++ {
			if word&(1<<uint(j)) != 0 {
				if buf.Len() > len("{") {
					buf.WriteByte(' ')
				}
				fmt.Fprintf(&buf, "%d", 64*i+j)
			}
		}
	}
	buf.WriteByte('}')
	return buf.String()
}

/*
练习6.1: 为bit数组实现下面这些方法

func (*IntSet) Len() int      // return the number of elements
func (*IntSet) Remove(x int)  // remove x from the set
func (*IntSet) Clear()        // remove all elements from the set
func (*IntSet) Copy() *IntSet // return a copy of the set
*/
func (s *IntSet) Len() int { // return the number of elements
	count := 0
	for _, x := range s.words {
		//fmt.Println(word)
		c := int(pc[byte(x>>(0*8))] +
			pc[byte(x>>(1*8))] +
			pc[byte(x>>(2*8))] +
			pc[byte(x>>(3*8))] +
			pc[byte(x>>(4*8))] +
			pc[byte(x>>(5*8))] +
			pc[byte(x>>(6*8))] +
			pc[byte(x>>(7*8))])
		count += c
	}
	return count
}

func (s *IntSet) Remove(x int) { // remove x from the set
	if s.Has(x) {
		word, bit := x/64, uint(x%64)
		s.words[word] ^= 1 << bit
	}

}

func (s *IntSet) Clear() { // remove all elements from the set
	for k := range s.words {
		s.words[k] = 0
	}
}

func (s *IntSet) Copy() *IntSet { // return a copy of the set
	var res IntSet
	for _, v := range s.words {
		res.words = append(res.words, v)
	}
	return &res
}

/*
练习 6.2：
定义一个变参方法(*IntSet).AddAll(...int)，这个方法可以为一组IntSet值求和(翻译问题吧?)，比如s.AddAll(1,2,3)。
*/

func (s *IntSet)AddAll(nums ...int) {
	for _, n := range nums {
		s.Add(n)
	}
}

/*
练习 6.3：
(*IntSet).UnionWith会用|操作符计算两个集合的并集，
我们再为IntSet实现另外的几个函数
IntersectWith(交集：元素在A集合B集合均出现),  A & B
DifferenceWith(差集：元素出现在A集合，未出现在B集合), A - B = A ^ (A & B)
SymmetricDifference(并差集：元素出现在A但没有出现在B，或者出现在B没有出现在A)。  (A-B) | (B-A)
*/

func (s *IntSet) IntersectWith(t *IntSet) {
	l := len(t.words)
	for i,_ := range s.words {
		if i < l {
			s.words[i] = s.words[i] & t.words[i]
		} else {
			s.words[i] = 0
		}
	}
}

func (s *IntSet) DifferenceWith(t *IntSet) {
	l := len(t.words)
	for i,_ := range s.words {
		if i < l {
			s.words[i] = s.words[i] ^ (s.words[i] & t.words[i])
		}
	}
}

func (s *IntSet) SymmetricDifference(t *IntSet) {
	l := len(t.words)
	for i,_ := range s.words {
		if i < l {
			s.words[i] = (s.words[i] ^ (s.words[i] & t.words[i])) | (t.words[i] ^ (s.words[i] & t.words[i]))
		}
	}

}

func main() {
	var x, y IntSet
	var z *IntSet

	x.Add(64)
	x.Add(2)
	z = x.Copy()
	fmt.Println(x.String())
	fmt.Println("---------")
	y.Add(9)
	y.Add(42)
	fmt.Println(y.String())
	fmt.Println("---------")
	x.UnionWith(&y)
	fmt.Println(x.String())
	x.Clear()
	x.Remove(64)
	x.Remove(1)
	fmt.Println(x.String())
	fmt.Println(z.String())
	fmt.Println(x.Has(9), x.Has(123))

	fmt.Println(x.Len())
	y.AddAll(1,1,2,3,5,8,13,21, 2112)
	z.AddAll(1,1,2,3,5,8)
	fmt.Println(z.String())
//	y.IntersectWith(z)
	fmt.Println(y.String())

	fmt.Println("---------")
	fmt.Println(z.String())
	fmt.Println(y.String())
	y.SymmetricDifference(z)
	fmt.Print(y.String())
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"os"

	"github.com/kleister/kleister-go/kleister"
	"github.com/urfave/cli"
)

// HandleFunc is the real handle implementation.
type HandleFunc func(c *cli.Context, client kleister.ClientAPI) error

// Handle wraps the command function handler.
func Handle(c *cli.Context, fn HandleFunc) {
	token := c.GlobalString("token")
	server := c.GlobalString("server")

	if server == "" {
		fmt.Fprintf(os.Stderr, "Error: You must provide the server address.\n")
		os.Exit(1)
	}

	if token == "" {
		fmt.Fprintf(os.Stderr, "Error: You must provide your access token.\n")
		os.Exit(2)
	}

	client := kleister.NewClientToken(
		server,
		token,
	)

	if err := fn(c, client); err != nil {
		fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error())
		os.Exit(3)
	}
}
<commit_msg>Made token optional<commit_after>package cmd

import (
	"fmt"
	"os"

	"github.com/kleister/kleister-go/kleister"
	"github.com/urfave/cli"
)

// HandleFunc is the real handle implementation.
type HandleFunc func(c *cli.Context, client kleister.ClientAPI) error

// Handle wraps the command function handler.
func Handle(c *cli.Context, fn HandleFunc) error {
	var (
		server = c.GlobalString("server")
		token  = c.GlobalString("token")

		client kleister.ClientAPI
	)

	if server == "" {
		fmt.Fprintf(os.Stderr, "Error: You must provide the server address.\n")
		os.Exit(1)
	}

	if token == "" {
		client = kleister.NewClient(
			server,
		)
	} else {
		client = kleister.NewClientToken(
			server,
			token,
		)
	}

	if err := fn(c, client); err != nil {
		fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error())
		os.Exit(2)
	}

	return nil
}
<|endoftext|>


<commit_before>package cmd

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"os"
	"path/filepath"

	"github.com/exercism/cli/api"
	"github.com/exercism/cli/config"
	"github.com/exercism/cli/workspace"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
	"github.com/spf13/viper"
)

// submitCmd lets people upload a solution to the website.
var submitCmd = &cobra.Command{
	Use:     "submit FILE1 [FILE2 ...]",
	Aliases: []string{"s"},
	Short:   "Submit your solution to an exercise.",
	Long: `Submit your solution to an Exercism exercise.

	Call the command with the list of files you want to submit.
`,
	RunE: func(cmd *cobra.Command, args []string) error {
		cfg := config.NewConfig()

		usrCfg := viper.New()
		usrCfg.AddConfigPath(cfg.Dir)
		usrCfg.SetConfigName("user")
		usrCfg.SetConfigType("json")
		// Ignore error. If the file doesn't exist, that is fine.
		_ = usrCfg.ReadInConfig()
		cfg.UserViperConfig = usrCfg

		v := viper.New()
		v.AddConfigPath(cfg.Dir)
		v.SetConfigName("cli")
		v.SetConfigType("json")
		// Ignore error. If the file doesn't exist, that is fine.
		_ = v.ReadInConfig()

		return runSubmit(cfg, cmd.Flags(), args)
	},
}

type submitContext struct {
	args   []string
	usrCfg *viper.Viper
}

func runSubmit(cfg config.Config, flags *pflag.FlagSet, args []string) error {
	usrCfg := cfg.UserViperConfig

	if err := validateUserConfig(usrCfg); err != nil {
		return err
	}

	ctx := &submitContext{args: args, usrCfg: usrCfg}

	if err := ctx.sanitizeArgs(); err != nil {
		return err
	}

	exerciseDir, err := ctx.exerciseDir()
	if err != nil {
		return err
	}

	exercise := workspace.NewExerciseFromDir(exerciseDir)

	migrationStatus, err := exercise.MigrateLegacyMetadataFile()
	if err != nil {
		return err
	}
	if verbose, _ := flags.GetBool("verbose"); verbose {
		fmt.Fprintf(Err, migrationStatus.String())
	}

	metadata, err := ctx.metadata(exerciseDir)
	if err != nil {
		return err
	}

	exercise.Documents, err = ctx.documents(exercise)
	if err != nil {
		return err
	}

	body := &bytes.Buffer{}
	writer := multipart.NewWriter(body)

	if err := ctx.writeFormFiles(writer, exercise.Documents); err != nil {
		return err
	}

	if err := ctx.submitRequest(metadata.ID, writer, body); err != nil {
		return err
	}

	msg := `

	Your solution has been submitted successfully.
	%s
`
	suffix := "View it at:\n\n    "
	if metadata.AutoApprove && metadata.Team == "" {
		suffix = "You can complete the exercise and unlock the next core exercise at:\n"
	}
	fmt.Fprintf(Err, msg, suffix)
	fmt.Fprintf(Out, "    %s\n\n", metadata.URL)
	return nil
}

func (ctx *submitContext) sanitizeArgs() error {
	for i, arg := range ctx.args {
		var err error
		arg, err = filepath.Abs(arg)
		if err != nil {
			return err
		}

		info, err := os.Lstat(arg)
		if err != nil {
			if os.IsNotExist(err) {
				msg := `

	The file you are trying to submit cannot be found.

		%s

		`
				return fmt.Errorf(msg, arg)
			}
			return err
		}
		if info.IsDir() {
			msg := `

	You are submitting a directory, which is not currently supported.

		%s

	Please change into the directory and provide the path to the file(s) you wish to submit

		%s submit FILENAME

			`
			return fmt.Errorf(msg, arg, BinaryName)
		}

		src, err := filepath.EvalSymlinks(arg)
		if err != nil {
			return err
		}
		ctx.args[i] = src
	}
	return nil
}

func (ctx *submitContext) exerciseDir() (string, error) {
	ws, err := workspace.New(ctx.usrCfg.GetString("workspace"))
	if err != nil {
		return "", err
	}

	var exerciseDir string
	for _, arg := range ctx.args {
		dir, err := ws.ExerciseDir(arg)
		if err != nil {
			if workspace.IsMissingMetadata(err) {
				return "", errors.New(msgMissingMetadata)
			}
			return "", err
		}
		if exerciseDir != "" && dir != exerciseDir {
			msg := `

	You are submitting files belonging to different solutions.
	Please submit the files for one solution at a time.

		`
			return "", errors.New(msg)
		}
		exerciseDir = dir
	}
	return exerciseDir, nil
}

func (ctx *submitContext) metadata(exerciseDir string) (*workspace.ExerciseMetadata, error) {
	metadata, err := workspace.NewExerciseMetadata(exerciseDir)
	if err != nil {
		return nil, err
	}

	exercise := workspace.NewExerciseFromDir(exerciseDir)
	if exercise.Slug != metadata.Exercise {
		// TODO: error msg should suggest running future doctor command
		msg := `

	The exercise directory does not match exercise slug in metadata:

		expected '%[1]s' but got '%[2]s'

	Please rename the directory '%[1]s' to '%[2]s' and try again.

		`
		return nil, fmt.Errorf(msg, exercise.Slug, metadata.Exercise)
	}

	if !metadata.IsRequester {
		// TODO: add test
		msg := `

	The solution you are submitting is not connected to your account.
	Please re-download the exercise to make sure it has the data it needs.

		%s download --exercise=%s --track=%s

		`
		return nil, fmt.Errorf(msg, BinaryName, metadata.Exercise, metadata.Track)
	}
	return metadata, nil
}

func (ctx *submitContext) documents(exercise workspace.Exercise) ([]workspace.Document, error) {
	docs := make([]workspace.Document, 0, len(ctx.args))
	for _, file := range ctx.args {
		// Don't submit empty files
		info, err := os.Stat(file)
		if err != nil {
			return nil, err
		}
		const maxFileSize int64 = 65535
		if info.Size() >= maxFileSize {
			msg := `

      The submitted file '%s' is larger than the max allowed file size of %d bytes.
      Please reduce the size of the file and try again.

			`
			return nil, fmt.Errorf(msg, file, maxFileSize)
		}
		if info.Size() == 0 {

			msg := `

    WARNING: Skipping empty file
             %s

		`
			fmt.Fprintf(Err, msg, file)
			continue
		}
		doc, err := workspace.NewDocument(exercise.Filepath(), file)
		if err != nil {
			return nil, err
		}
		docs = append(docs, doc)
	}
	if len(docs) == 0 {
		msg := `

	No files found to submit.

		`
		return nil, errors.New(msg)
	}
	return docs, nil
}

func (ctx *submitContext) writeFormFiles(writer *multipart.Writer, docs []workspace.Document) error {
	for _, doc := range docs {
		file, err := os.Open(doc.Filepath())
		if err != nil {
			return err
		}
		defer file.Close()

		part, err := writer.CreateFormFile("files[]", doc.Path())
		if err != nil {
			return err
		}
		_, err = io.Copy(part, file)
		if err != nil {
			return err
		}
	}
	if err := writer.Close(); err != nil {
		return err
	}
	return nil
}

func (ctx *submitContext) submitRequest(id string, writer *multipart.Writer, body *bytes.Buffer) error {
	client, err := api.NewClient(ctx.usrCfg.GetString("token"), ctx.usrCfg.GetString("apibaseurl"))
	if err != nil {
		return err
	}
	url := fmt.Sprintf("%s/solutions/%s", ctx.usrCfg.GetString("apibaseurl"), id)
	req, err := client.NewRequest("PATCH", url, body)
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", writer.FormDataContentType())

	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode == http.StatusBadRequest {
		var jsonErrBody apiErrorMessage
		if err := json.NewDecoder(resp.Body).Decode(&jsonErrBody); err != nil {
			return fmt.Errorf("failed to parse error response - %s", err)
		}

		return fmt.Errorf(jsonErrBody.Error.Message)
	}

	bb := &bytes.Buffer{}
	_, err = bb.ReadFrom(resp.Body)
	if err != nil {
		return err
	}
	return nil
}

func init() {
	RootCmd.AddCommand(submitCmd)
}

type apiErrorMessage struct {
	Error struct {
		Type    string `json:"type"`
		Message string `json:"message"`
	} `json:"error,omitempty"`
}
<commit_msg>Simplify documents param<commit_after>package cmd

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"os"
	"path/filepath"

	"github.com/exercism/cli/api"
	"github.com/exercism/cli/config"
	"github.com/exercism/cli/workspace"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
	"github.com/spf13/viper"
)

// submitCmd lets people upload a solution to the website.
var submitCmd = &cobra.Command{
	Use:     "submit FILE1 [FILE2 ...]",
	Aliases: []string{"s"},
	Short:   "Submit your solution to an exercise.",
	Long: `Submit your solution to an Exercism exercise.

	Call the command with the list of files you want to submit.
`,
	RunE: func(cmd *cobra.Command, args []string) error {
		cfg := config.NewConfig()

		usrCfg := viper.New()
		usrCfg.AddConfigPath(cfg.Dir)
		usrCfg.SetConfigName("user")
		usrCfg.SetConfigType("json")
		// Ignore error. If the file doesn't exist, that is fine.
		_ = usrCfg.ReadInConfig()
		cfg.UserViperConfig = usrCfg

		v := viper.New()
		v.AddConfigPath(cfg.Dir)
		v.SetConfigName("cli")
		v.SetConfigType("json")
		// Ignore error. If the file doesn't exist, that is fine.
		_ = v.ReadInConfig()

		return runSubmit(cfg, cmd.Flags(), args)
	},
}

type submitContext struct {
	args   []string
	usrCfg *viper.Viper
}

func runSubmit(cfg config.Config, flags *pflag.FlagSet, args []string) error {
	usrCfg := cfg.UserViperConfig

	if err := validateUserConfig(usrCfg); err != nil {
		return err
	}

	ctx := &submitContext{args: args, usrCfg: usrCfg}

	if err := ctx.sanitizeArgs(); err != nil {
		return err
	}

	exerciseDir, err := ctx.exerciseDir()
	if err != nil {
		return err
	}

	exercise := workspace.NewExerciseFromDir(exerciseDir)

	migrationStatus, err := exercise.MigrateLegacyMetadataFile()
	if err != nil {
		return err
	}
	if verbose, _ := flags.GetBool("verbose"); verbose {
		fmt.Fprintf(Err, migrationStatus.String())
	}

	metadata, err := ctx.metadata(exerciseDir)
	if err != nil {
		return err
	}

	exercise.Documents, err = ctx.documents(exerciseDir)
	if err != nil {
		return err
	}

	body := &bytes.Buffer{}
	writer := multipart.NewWriter(body)

	if err := ctx.writeFormFiles(writer, exercise.Documents); err != nil {
		return err
	}

	if err := ctx.submitRequest(metadata.ID, writer, body); err != nil {
		return err
	}

	msg := `

	Your solution has been submitted successfully.
	%s
`
	suffix := "View it at:\n\n    "
	if metadata.AutoApprove && metadata.Team == "" {
		suffix = "You can complete the exercise and unlock the next core exercise at:\n"
	}
	fmt.Fprintf(Err, msg, suffix)
	fmt.Fprintf(Out, "    %s\n\n", metadata.URL)
	return nil
}

func (ctx *submitContext) sanitizeArgs() error {
	for i, arg := range ctx.args {
		var err error
		arg, err = filepath.Abs(arg)
		if err != nil {
			return err
		}

		info, err := os.Lstat(arg)
		if err != nil {
			if os.IsNotExist(err) {
				msg := `

	The file you are trying to submit cannot be found.

		%s

		`
				return fmt.Errorf(msg, arg)
			}
			return err
		}
		if info.IsDir() {
			msg := `

	You are submitting a directory, which is not currently supported.

		%s

	Please change into the directory and provide the path to the file(s) you wish to submit

		%s submit FILENAME

			`
			return fmt.Errorf(msg, arg, BinaryName)
		}

		src, err := filepath.EvalSymlinks(arg)
		if err != nil {
			return err
		}
		ctx.args[i] = src
	}
	return nil
}

func (ctx *submitContext) exerciseDir() (string, error) {
	ws, err := workspace.New(ctx.usrCfg.GetString("workspace"))
	if err != nil {
		return "", err
	}

	var exerciseDir string
	for _, arg := range ctx.args {
		dir, err := ws.ExerciseDir(arg)
		if err != nil {
			if workspace.IsMissingMetadata(err) {
				return "", errors.New(msgMissingMetadata)
			}
			return "", err
		}
		if exerciseDir != "" && dir != exerciseDir {
			msg := `

	You are submitting files belonging to different solutions.
	Please submit the files for one solution at a time.

		`
			return "", errors.New(msg)
		}
		exerciseDir = dir
	}
	return exerciseDir, nil
}

func (ctx *submitContext) metadata(exerciseDir string) (*workspace.ExerciseMetadata, error) {
	metadata, err := workspace.NewExerciseMetadata(exerciseDir)
	if err != nil {
		return nil, err
	}

	exercise := workspace.NewExerciseFromDir(exerciseDir)
	if exercise.Slug != metadata.Exercise {
		// TODO: error msg should suggest running future doctor command
		msg := `

	The exercise directory does not match exercise slug in metadata:

		expected '%[1]s' but got '%[2]s'

	Please rename the directory '%[1]s' to '%[2]s' and try again.

		`
		return nil, fmt.Errorf(msg, exercise.Slug, metadata.Exercise)
	}

	if !metadata.IsRequester {
		// TODO: add test
		msg := `

	The solution you are submitting is not connected to your account.
	Please re-download the exercise to make sure it has the data it needs.

		%s download --exercise=%s --track=%s

		`
		return nil, fmt.Errorf(msg, BinaryName, metadata.Exercise, metadata.Track)
	}
	return metadata, nil
}

func (ctx *submitContext) documents(exerciseDir string) ([]workspace.Document, error) {
	docs := make([]workspace.Document, 0, len(ctx.args))
	for _, file := range ctx.args {
		// Don't submit empty files
		info, err := os.Stat(file)
		if err != nil {
			return nil, err
		}
		const maxFileSize int64 = 65535
		if info.Size() >= maxFileSize {
			msg := `

      The submitted file '%s' is larger than the max allowed file size of %d bytes.
      Please reduce the size of the file and try again.

			`
			return nil, fmt.Errorf(msg, file, maxFileSize)
		}
		if info.Size() == 0 {

			msg := `

    WARNING: Skipping empty file
             %s

		`
			fmt.Fprintf(Err, msg, file)
			continue
		}
		doc, err := workspace.NewDocument(exerciseDir, file)
		if err != nil {
			return nil, err
		}
		docs = append(docs, doc)
	}
	if len(docs) == 0 {
		msg := `

	No files found to submit.

		`
		return nil, errors.New(msg)
	}
	return docs, nil
}

func (ctx *submitContext) writeFormFiles(writer *multipart.Writer, docs []workspace.Document) error {
	for _, doc := range docs {
		file, err := os.Open(doc.Filepath())
		if err != nil {
			return err
		}
		defer file.Close()

		part, err := writer.CreateFormFile("files[]", doc.Path())
		if err != nil {
			return err
		}
		_, err = io.Copy(part, file)
		if err != nil {
			return err
		}
	}
	if err := writer.Close(); err != nil {
		return err
	}
	return nil
}

func (ctx *submitContext) submitRequest(id string, writer *multipart.Writer, body *bytes.Buffer) error {
	client, err := api.NewClient(ctx.usrCfg.GetString("token"), ctx.usrCfg.GetString("apibaseurl"))
	if err != nil {
		return err
	}
	url := fmt.Sprintf("%s/solutions/%s", ctx.usrCfg.GetString("apibaseurl"), id)
	req, err := client.NewRequest("PATCH", url, body)
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", writer.FormDataContentType())

	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode == http.StatusBadRequest {
		var jsonErrBody apiErrorMessage
		if err := json.NewDecoder(resp.Body).Decode(&jsonErrBody); err != nil {
			return fmt.Errorf("failed to parse error response - %s", err)
		}

		return fmt.Errorf(jsonErrBody.Error.Message)
	}

	bb := &bytes.Buffer{}
	_, err = bb.ReadFrom(resp.Body)
	if err != nil {
		return err
	}
	return nil
}

func init() {
	RootCmd.AddCommand(submitCmd)
}

type apiErrorMessage struct {
	Error struct {
		Type    string `json:"type"`
		Message string `json:"message"`
	} `json:"error,omitempty"`
}
<|endoftext|>


<commit_before>// Copyright (c) 2022 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package zanzibar

import (
	"context"
	"time"

	jsonschema "github.com/mcuadros/go-jsonschema-generator"
	"github.com/uber-go/tally"
)

const (
	middlewareRequestLatencyTag  = "middleware.request.latency"
	middlewareResponseLatencyTag = "middleware.response.latency"
	middlewareRequestStatusTag   = "middleware.request.status"
)

// MiddlewareStack is a stack of Middleware Handlers that can be invoked as an Handle.
// MiddlewareStack middlewares are evaluated for requests in the order that they are added to the stack
// followed by the underlying HandlerFn. The middleware responses are then executed in reverse.
type MiddlewareStack struct {
	middlewares []MiddlewareHandle
	handle      HandlerFn
}

// NewStack returns a new MiddlewareStack instance with no middleware preconfigured.
func NewStack(middlewares []MiddlewareHandle,
	handle HandlerFn) *MiddlewareStack {
	return &MiddlewareStack{
		handle:      handle,
		middlewares: middlewares,
	}
}

// Middlewares returns a list of all the handlers in the current MiddlewareStack.
func (m *MiddlewareStack) Middlewares() []MiddlewareHandle {
	return m.middlewares
}

// MiddlewareHandle used to define middleware
type MiddlewareHandle interface {
	// implement HandleRequest for your middleware. Return false
	// if the handler writes to the response body.
	HandleRequest(
		ctx context.Context,
		req *ServerHTTPRequest,
		res *ServerHTTPResponse,
		shared SharedState,
	) (context.Context, bool)
	// implement HandleResponse for your middleware. Return false
	// if the handler writes to the response body.
	HandleResponse(
		ctx context.Context,
		res *ServerHTTPResponse,
		shared SharedState,
	) context.Context
	// return any shared state for this middleware.
	JSONSchema() *jsonschema.Document
	Name() string
}

// SharedState used to access other middlewares in the chain.
type SharedState struct {
	middlewareDict map[string]interface{}
}

// NewSharedState constructs a ShardState
func NewSharedState(middlewares []MiddlewareHandle) SharedState {
	sharedState := SharedState{}
	sharedState.middlewareDict = make(map[string]interface{})

	for i := 0; i < len(middlewares); i++ {
		sharedState.middlewareDict[middlewares[i].Name()] = nil
	}
	return sharedState
}

// GetState returns the state from a different middleware
func (s SharedState) GetState(name string) interface{} {
	return s.middlewareDict[name]
}

// SetState sets value of a middleware shared state
func (s SharedState) SetState(m MiddlewareHandle, state interface{}) {
	s.middlewareDict[m.Name()] = state
}

// Handle executes the middlewares in a stack and underlying handler.
func (m *MiddlewareStack) Handle(
	ctx context.Context,
	req *ServerHTTPRequest,
	res *ServerHTTPResponse) context.Context {

	shared := NewSharedState(m.middlewares)
	middlewareRequestStartTime := time.Now()

	for i := 0; i < len(m.middlewares); i++ {
		ctx, ok := m.middlewares[i].HandleRequest(ctx, req, res, shared)
		// If a middleware errors and writes to the response header
		// then abort the rest of the stack and evaluate the response
		// handlers for the middlewares seen so far.
		if ok == false {
			//record latency for middlewares requests in unsuccessful case as the middleware requests calls are terminated
			m.recordLatency(middlewareRequestLatencyTag, middlewareRequestStartTime, req.scope)

			middlewareResponseStartTime := time.Now() // start the timer for middleware responses
			for j := i; j >= 0; j-- {
				m.middlewares[j].HandleResponse(ctx, res, shared)
			}
			//record latency for middlewares responses in unsuccessful case
			m.recordLatency(middlewareResponseLatencyTag, middlewareResponseStartTime, req.scope)

			//for error metrics only emit when there is gateway error and not request error
			// the percentage can be calculated via error_count/total_request
			if res.pendingStatusCode >= 500 {
				m.emitAvailabilityError(middlewareRequestStatusTag, m.middlewares[i].Name(), req.scope)
			}
			return ctx
		}
	}
	// record latency for middlewares requests in successful case
	m.recordLatency(middlewareRequestLatencyTag, middlewareRequestStartTime, req.scope)

	ctx = m.handle(ctx, req, res)

	middlewareResponseStartTime := time.Now()
	for i := len(m.middlewares) - 1; i >= 0; i-- {
		m.middlewares[i].HandleResponse(ctx, res, shared)
	}
	// record latency for middlewares responses in successful case
	m.recordLatency(middlewareResponseLatencyTag, middlewareResponseStartTime, req.scope)
	return ctx
}

// recordLatency measures the latency as per the tagName and start time given.
func (m *MiddlewareStack) recordLatency(tagName string, startTime time.Time, scope tally.Scope) {
	elapsed := time.Now().Sub(startTime)
	scope.Timer(tagName).Record(elapsed)
	scope.Histogram(tagName, tally.DefaultBuckets).RecordDuration(elapsed)
}

// emitAvailability is used to increment the error counter for a particular tagName.
func (m *MiddlewareStack) emitAvailabilityError(tagName string, middlewareName string, scope tally.Scope) {
	tagged := scope.Tagged(map[string]string{
		scopeTagStatus: "error",
		scopeTagMiddleWare: middlewareName,
	})
	tagged.Counter(tagName).Inc(1)
}
<commit_msg>fixed indentation<commit_after>// Copyright (c) 2022 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package zanzibar

import (
	"context"
	"time"

	jsonschema "github.com/mcuadros/go-jsonschema-generator"
	"github.com/uber-go/tally"
)

const (
	middlewareRequestLatencyTag  = "middleware.request.latency"
	middlewareResponseLatencyTag = "middleware.response.latency"
	middlewareRequestStatusTag   = "middleware.request.status"
)

// MiddlewareStack is a stack of Middleware Handlers that can be invoked as an Handle.
// MiddlewareStack middlewares are evaluated for requests in the order that they are added to the stack
// followed by the underlying HandlerFn. The middleware responses are then executed in reverse.
type MiddlewareStack struct {
	middlewares []MiddlewareHandle
	handle      HandlerFn
}

// NewStack returns a new MiddlewareStack instance with no middleware preconfigured.
func NewStack(middlewares []MiddlewareHandle,
	handle HandlerFn) *MiddlewareStack {
	return &MiddlewareStack{
		handle:      handle,
		middlewares: middlewares,
	}
}

// Middlewares returns a list of all the handlers in the current MiddlewareStack.
func (m *MiddlewareStack) Middlewares() []MiddlewareHandle {
	return m.middlewares
}

// MiddlewareHandle used to define middleware
type MiddlewareHandle interface {
	// implement HandleRequest for your middleware. Return false
	// if the handler writes to the response body.
	HandleRequest(
		ctx context.Context,
		req *ServerHTTPRequest,
		res *ServerHTTPResponse,
		shared SharedState,
	) (context.Context, bool)
	// implement HandleResponse for your middleware. Return false
	// if the handler writes to the response body.
	HandleResponse(
		ctx context.Context,
		res *ServerHTTPResponse,
		shared SharedState,
	) context.Context
	// return any shared state for this middleware.
	JSONSchema() *jsonschema.Document
	Name() string
}

// SharedState used to access other middlewares in the chain.
type SharedState struct {
	middlewareDict map[string]interface{}
}

// NewSharedState constructs a ShardState
func NewSharedState(middlewares []MiddlewareHandle) SharedState {
	sharedState := SharedState{}
	sharedState.middlewareDict = make(map[string]interface{})

	for i := 0; i < len(middlewares); i++ {
		sharedState.middlewareDict[middlewares[i].Name()] = nil
	}
	return sharedState
}

// GetState returns the state from a different middleware
func (s SharedState) GetState(name string) interface{} {
	return s.middlewareDict[name]
}

// SetState sets value of a middleware shared state
func (s SharedState) SetState(m MiddlewareHandle, state interface{}) {
	s.middlewareDict[m.Name()] = state
}

// Handle executes the middlewares in a stack and underlying handler.
func (m *MiddlewareStack) Handle(
	ctx context.Context,
	req *ServerHTTPRequest,
	res *ServerHTTPResponse) context.Context {

	shared := NewSharedState(m.middlewares)
	middlewareRequestStartTime := time.Now()

	for i := 0; i < len(m.middlewares); i++ {
		ctx, ok := m.middlewares[i].HandleRequest(ctx, req, res, shared)
		// If a middleware errors and writes to the response header
		// then abort the rest of the stack and evaluate the response
		// handlers for the middlewares seen so far.
		if ok == false {
			//record latency for middlewares requests in unsuccessful case as the middleware requests calls are terminated
			m.recordLatency(middlewareRequestLatencyTag, middlewareRequestStartTime, req.scope)

			middlewareResponseStartTime := time.Now() // start the timer for middleware responses
			for j := i; j >= 0; j-- {
				m.middlewares[j].HandleResponse(ctx, res, shared)
			}
			//record latency for middlewares responses in unsuccessful case
			m.recordLatency(middlewareResponseLatencyTag, middlewareResponseStartTime, req.scope)

			//for error metrics only emit when there is gateway error and not request error
			// the percentage can be calculated via error_count/total_request
			if res.pendingStatusCode >= 500 {
				m.emitAvailabilityError(middlewareRequestStatusTag, m.middlewares[i].Name(), req.scope)
			}
			return ctx
		}
	}
	// record latency for middlewares requests in successful case
	m.recordLatency(middlewareRequestLatencyTag, middlewareRequestStartTime, req.scope)

	ctx = m.handle(ctx, req, res)

	middlewareResponseStartTime := time.Now()
	for i := len(m.middlewares) - 1; i >= 0; i-- {
		m.middlewares[i].HandleResponse(ctx, res, shared)
	}
	// record latency for middlewares responses in successful case
	m.recordLatency(middlewareResponseLatencyTag, middlewareResponseStartTime, req.scope)
	return ctx
}

// recordLatency measures the latency as per the tagName and start time given.
func (m *MiddlewareStack) recordLatency(tagName string, startTime time.Time, scope tally.Scope) {
	elapsed := time.Now().Sub(startTime)
	scope.Timer(tagName).Record(elapsed)
	scope.Histogram(tagName, tally.DefaultBuckets).RecordDuration(elapsed)
}

// emitAvailability is used to increment the error counter for a particular tagName.
func (m *MiddlewareStack) emitAvailabilityError(tagName string, middlewareName string, scope tally.Scope) {
	tagged := scope.Tagged(map[string]string{
		scopeTagStatus:     "error",
		scopeTagMiddleWare: middlewareName,
	})
	tagged.Counter(tagName).Inc(1)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"testing"
)

// TODO: read source files
func TestCompile(t *testing.T) {
	var sourceFiles []string
	for _, source := range sourceFiles {
		f, err := os.Open(source)
		if err != nil {
			t.Fail()
		}
		defer f.Close()
		tokenGrid, err := lexer(os.Stdin)
		if err != nil {
			t.Fail()
		}
		if _, err := parse(tokenGrid); err != nil {
			t.Fail()
		}
	}
}

func TestZeroSink(t *testing.T) {
	r := strings.NewReader("0!")
	tokenGrid, err := lexer(r)
	if err != nil {
		t.Fail()
	}
	program, err := parse(tokenGrid)
	if err != nil {
		t.Fail()
	}

	output := make(chan Value, 1)
	input := make(chan Value, 1)
	halt := make(chan int, 1)

	go func() {
		for i := 0; i < 10; i += 1 {
			input <- 0 // Any data
		}
		input <- 0 // Latency of 1
		close(input)
	}()

	go program.Run(input, output, halt)

	<-output // Ignore: latency of 1
	for i := 0; i < 10; i += 1 {
		v, ok := <-output
		t.Log("zero", v, ok)
		if !ok || v != 0 {
			t.Fatal("wrong data")
		}
	}
}

func TestSourceSink(t *testing.T) {
	sources := []string{"@!", "!@", "@\n!", "!\n@"}
	for _, source := range sources {
		r := strings.NewReader(source)
		tokenGrid, err := lexer(r)
		if err != nil {
			t.Fatal("lexer failed")
		}

		program, err := parse(tokenGrid)
		if err != nil {
			t.Fatal("parser failed")
		}

		output := make(chan Value, 1)
		input := make(chan Value, 1)
		halt := make(chan int, 1)
		data := []Value{1, 2, 3, 4, 5}

		go func() {
			for _, v := range data {
				t.Log("send:", v)
				input <- v
			}
			input <- 0 // Latency of 1
			close(input)
		}()

		go program.Run(input, output, halt)

		<-output // Ignore: latency of 1
		i := 0
		for v := range output {
			t.Log("recv:", v)
			if v != data[i] {
				t.Fatal("wrong data")
			}
			i += 1
		}
	}
}

func TestInterpreter(t *testing.T) {
	dirs, err := filepath.Glob("testdata/*")
	if err != nil {
		t.Fatal(err)
	}
	if len(dirs) == 0 {
		wd, _ := os.Getwd()
		t.Fatal("no tests in testdata found in: ", wd)
	}
	for _, dir := range dirs {
		fin, err := os.Open(filepath.Join(dir, "input.txt"))
		if err != nil {
			t.Fatal(err)
		}
		defer fin.Close()

		fout, err := ioutil.TempFile("", "test")
		if err != nil {
			t.Fatal(err)
		}
		defer func() {
			fout.Close()
			os.Remove(fout.Name())
		}()

		wd, _ := os.Getwd()
		cmd := exec.Command(filepath.Join(wd, "cubeflow"), "-o", fout.Name(), filepath.Join(dir, "program.cf"))
		cmd.Stdin = fin
		if err = cmd.Run(); err != nil {
			t.Fatal(err, cmd.Path)
		}

		buffer := bytes.Buffer{}
		cmd = exec.Command("diff", fout.Name(), filepath.Join(dir, "output.txt"))
		cmd.Stdout = &buffer
		if err = cmd.Run(); err != nil {
			t.Fatal(string(buffer.Bytes()))
		}
	}
}
<commit_msg>Fix binary name to LayerFlow<commit_after>package main

import (
	"bytes"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"testing"
)

// TODO: read source files
func TestCompile(t *testing.T) {
	var sourceFiles []string
	for _, source := range sourceFiles {
		f, err := os.Open(source)
		if err != nil {
			t.Fail()
		}
		defer f.Close()
		tokenGrid, err := lexer(os.Stdin)
		if err != nil {
			t.Fail()
		}
		if _, err := parse(tokenGrid); err != nil {
			t.Fail()
		}
	}
}

func TestZeroSink(t *testing.T) {
	r := strings.NewReader("0!")
	tokenGrid, err := lexer(r)
	if err != nil {
		t.Fail()
	}
	program, err := parse(tokenGrid)
	if err != nil {
		t.Fail()
	}

	output := make(chan Value, 1)
	input := make(chan Value, 1)
	halt := make(chan int, 1)

	go func() {
		for i := 0; i < 10; i += 1 {
			input <- 0 // Any data
		}
		input <- 0 // Latency of 1
		close(input)
	}()

	go program.Run(input, output, halt)

	<-output // Ignore: latency of 1
	for i := 0; i < 10; i += 1 {
		v, ok := <-output
		t.Log("zero", v, ok)
		if !ok || v != 0 {
			t.Fatal("wrong data")
		}
	}
}

func TestSourceSink(t *testing.T) {
	sources := []string{"@!", "!@", "@\n!", "!\n@"}
	for _, source := range sources {
		r := strings.NewReader(source)
		tokenGrid, err := lexer(r)
		if err != nil {
			t.Fatal("lexer failed")
		}

		program, err := parse(tokenGrid)
		if err != nil {
			t.Fatal("parser failed")
		}

		output := make(chan Value, 1)
		input := make(chan Value, 1)
		halt := make(chan int, 1)
		data := []Value{1, 2, 3, 4, 5}

		go func() {
			for _, v := range data {
				t.Log("send:", v)
				input <- v
			}
			input <- 0 // Latency of 1
			close(input)
		}()

		go program.Run(input, output, halt)

		<-output // Ignore: latency of 1
		i := 0
		for v := range output {
			t.Log("recv:", v)
			if v != data[i] {
				t.Fatal("wrong data")
			}
			i += 1
		}
	}
}

func TestInterpreter(t *testing.T) {
	dirs, err := filepath.Glob("testdata/*")
	if err != nil {
		t.Fatal(err)
	}
	if len(dirs) == 0 {
		wd, _ := os.Getwd()
		t.Fatal("no tests in testdata found in: ", wd)
	}
	for _, dir := range dirs {
		fin, err := os.Open(filepath.Join(dir, "input.txt"))
		if err != nil {
			t.Fatal(err)
		}
		defer fin.Close()

		fout, err := ioutil.TempFile("", "test")
		if err != nil {
			t.Fatal(err)
		}
		defer func() {
			fout.Close()
			os.Remove(fout.Name())
		}()

		wd, _ := os.Getwd()
		cmd := exec.Command(filepath.Join(wd, "LayerFlow"), "-o", fout.Name(), filepath.Join(dir, "program.cf"))
		cmd.Stdin = fin
		if err = cmd.Run(); err != nil {
			t.Fatal(err, cmd.Path)
		}

		buffer := bytes.Buffer{}
		cmd = exec.Command("diff", fout.Name(), filepath.Join(dir, "output.txt"))
		cmd.Stdout = &buffer
		if err = cmd.Run(); err != nil {
			t.Fatal(string(buffer.Bytes()))
		}
	}
}
<|endoftext|>


<commit_before>package broker

import (
	"errors"
	"fmt"
	"strings"

	"github.com/streadway/amqp"
)

var (
	format = "amqp://%v:%v@%v:%d/"

	// Channel Connection defaults
	user = "guest"
	pass = "guest"
	host = "localhost"
	port = 5672

	// dispatching defauls
	exchangeName     = "celery"
	routingKey       = "celery"
	queueName        = "celery"
	exchangeType     = "direct"
	durable          = true
	DeleteWhenUnUsed = false
	exclusive        = false
	noWait           = false
	autoAck          = false
)

type AmqpConnection struct {
	// Connection params

	// Connection stuff
	conn    *amqp.Connection
	channel *amqp.Channel

	// Use one
	queue    *Queue
	exchange *Exchange
}

// Default constructor
func NewAmqpConnection(params map[string]string) (*AmqpConnection, error) {
	// TODO use params instead of defaults
	return new(AmqpConnection), nil
}

// Creates a new amqp connection
func (c *AmqpConnection) Connect() error {
	var err error
	connString := fmt.Sprintf(format, user, pass, host, port)

	c.conn, err = amqp.Dial(connString)
	if err != nil {
		return errors.New("Failed to connect to RabbitMQ")
	}

	c.channel, err = c.createChannel()
	if err != nil {
		return err
	}

	// Set the queue and the exchange
	c.queue = &Queue{
		name:             queueName,
		durable:          durable,
		deleteWhenUnUsed: DeleteWhenUnUsed,
		exclusive:        exclusive,
		noWait:           noWait,
		params:           nil,
	}

	err = c.declareQueue(c.queue)
	if err != nil {
		return err
	}

	c.exchange = &Exchange{
		name:             queueName,
		exchangeType:     exchangeType,
		durable:          durable,
		deleteWhenUnUsed: DeleteWhenUnUsed,
		exclusive:        exclusive,
		noWait:           noWait,
		params:           nil,
		bindings:         []*Binding{},
	}

	err = c.declareExchange(c.exchange)
	if err != nil {
		return err
	}

	// One exchange to rule them all,
	// One queue to find them,
	// One routing key to bring them all and in the darkness bind them
	bindingName := strings.Join([]string{exchangeName, routingKey}, "/")
	_, err = c.bind(bindingName, routingKey, c.exchange, c.queue)
	if err != nil {
		return err
	}

	return nil
}

// Closes current amqp connection
func (c *AmqpConnection) Disconnect() error {
	err := c.channel.Close()
	if err != nil {
		return errors.New("Failed to close channel")
	}

	err = c.conn.Close()
	if err != nil {
		return errors.New("Failed to close connection")
	}

	return nil
}

// Start consumming from the connection, returns a channel where the
// messages will be delivered
func (c *AmqpConnection) Consume() (<-chan *Message, error) {
	msgs, err := c.channel.Consume(c.queue.name, "", autoAck, exclusive, false, noWait, nil)

	if err != nil {
		return nil, errors.New("Failed consuming queue")
	}

	resultChannel := make(chan *Message)

	// this coroutine will get the messages from the amqp and will convert to a
	// custom local format
	go func() {
		for m := range msgs {
			resultChannel <- c.convertMessage(&m)
		}
	}()

	return resultChannel, nil
}

func (c AmqpConnection) createChannel() (*amqp.Channel, error) {

	channel, err := c.conn.Channel()

	if err != nil {
		return nil, errors.New("Failed to connect to RabbitMQ")
	}

	return channel, nil
}

func (c *AmqpConnection) declareQueue(q *Queue) error {

	// We only need queue information after declaring it
	_, err := c.channel.QueueDeclare(
		q.name,
		q.durable,
		q.deleteWhenUnUsed,
		q.exclusive,
		q.noWait,
		q.params,
	)

	if err != nil {
		return errors.New("Failed to declare queue")
	}

	return nil
}

func (c *AmqpConnection) declareExchange(e *Exchange) error {

	// We only need queue information after declaring it
	err := c.channel.ExchangeDeclare(
		e.name,
		e.exchangeType,
		e.durable,
		e.deleteWhenUnUsed,
		e.exclusive,
		e.noWait,
		e.params,
	)

	if err != nil {
		return errors.New("Failed to declare exchange")
	}

	return nil
}

// Binds the queue to an exchange and creates a Bindind object
func (c *AmqpConnection) bind(name, routingKey string, e *Exchange, q *Queue) (*Binding, error) {
	err := c.channel.QueueBind(q.name, routingKey, e.name, q.noWait, nil)
	if err != nil {
		return nil, errors.New("Failed to Bind queue to exchange")
	}

	b := &Binding{
		name:       name,
		routingKey: routingKey,
		queue:      q,
		exchange:   e,
	}

	// This way we could obtain all the bindings of each exchange
	e.bindings = append(e.bindings, b)

	return b, nil

}

// Converts an amqp message to a custom message
func (c *AmqpConnection) convertMessage(m *amqp.Delivery) *Message {
	return &Message{
		ContentType: m.ContentType,
		Body:        m.Body,
		Original:    m,
	}
}

func (c *AmqpConnection) Ack(m *Message) error {
	d := m.Original.(*amqp.Delivery)
	return d.Ack(false)
}

// Aux types
type Queue struct {
	name             string
	durable          bool
	deleteWhenUnUsed bool
	exclusive        bool
	noWait           bool
	params           amqp.Table
}

type Exchange struct {
	name             string
	exchangeType     string
	durable          bool
	deleteWhenUnUsed bool
	exclusive        bool
	noWait           bool
	params           amqp.Table
	bindings         []*Binding //For now use one only
}

type Binding struct {
	name       string
	routingKey string
	queue      *Queue
	exchange   *Exchange
}
<commit_msg>Added simple logging<commit_after>package broker

import (
	"errors"
	"fmt"
	"log"
	"strings"

	"github.com/streadway/amqp"
)

var (
	format = "amqp://%v:%v@%v:%d/"

	// Channel Connection defaults
	user = "guest"
	pass = "guest"
	host = "localhost"
	port = 5672

	// dispatching defauls
	exchangeName     = "celery"
	routingKey       = "celery"
	queueName        = "celery"
	exchangeType     = "direct"
	durable          = true
	DeleteWhenUnUsed = false
	exclusive        = false
	noWait           = false
	autoAck          = false
)

type AmqpConnection struct {
	// Connection params

	// Connection stuff
	conn    *amqp.Connection
	channel *amqp.Channel

	// Use one
	queue    *Queue
	exchange *Exchange
}

// Default constructor
func NewAmqpConnection(params map[string]string) (*AmqpConnection, error) {
	// TODO use params instead of defaults
	log.Println("New AMQP connection object created")
	return new(AmqpConnection), nil
}

// Creates a new amqp connection
func (c *AmqpConnection) Connect() error {
	var err error
	connString := fmt.Sprintf(format, user, pass, host, port)

	c.conn, err = amqp.Dial(connString)
	if err != nil {
		return errors.New("Failed to connect to RabbitMQ")
	}

	c.channel, err = c.createChannel()
	if err != nil {
		return err
	}

	// Set the queue and the exchange
	c.queue = &Queue{
		name:             queueName,
		durable:          durable,
		deleteWhenUnUsed: DeleteWhenUnUsed,
		exclusive:        exclusive,
		noWait:           noWait,
		params:           nil,
	}

	err = c.declareQueue(c.queue)
	if err != nil {
		return err
	}

	c.exchange = &Exchange{
		name:             queueName,
		exchangeType:     exchangeType,
		durable:          durable,
		deleteWhenUnUsed: DeleteWhenUnUsed,
		exclusive:        exclusive,
		noWait:           noWait,
		params:           nil,
		bindings:         []*Binding{},
	}

	err = c.declareExchange(c.exchange)
	if err != nil {
		return err
	}

	// One exchange to rule them all,
	// One queue to find them,
	// One routing key to bring them all and in the darkness bind them
	bindingName := strings.Join([]string{exchangeName, routingKey}, "/")
	_, err = c.bind(bindingName, routingKey, c.exchange, c.queue)
	if err != nil {
		return err
	}

	return nil
}

// Closes current amqp connection
func (c *AmqpConnection) Disconnect() error {
	err := c.channel.Close()
	if err != nil {
		return errors.New("Failed to close channel")
	}

	err = c.conn.Close()
	if err != nil {
		return errors.New("Failed to close connection")
	}

	log.Println("Connected to Rabbitmq")
	return nil
}

// Start consumming from the connection, returns a channel where the
// messages will be delivered
func (c *AmqpConnection) Consume() (<-chan *Message, error) {
	msgs, err := c.channel.Consume(c.queue.name, "", autoAck, exclusive, false, noWait, nil)

	if err != nil {
		log.Println("Failed consuming queue")
		return nil, errors.New("Failed consuming queue")
	}

	resultChannel := make(chan *Message)

	// this coroutine will get the messages from the amqp and will convert to a
	// custom local format
	log.Println("Start consuming from queue")
	go func() {
		for m := range msgs {
			log.Println("Received package")
			resultChannel <- c.convertMessage(&m)
		}
	}()

	return resultChannel, nil
}

func (c AmqpConnection) createChannel() (*amqp.Channel, error) {

	channel, err := c.conn.Channel()

	if err != nil {
		log.Println("Failed to connect to RabbitMQ")
		return nil, errors.New("Failed to connect to RabbitMQ")
	}
	log.Println("Created channel")
	return channel, nil
}

func (c *AmqpConnection) declareQueue(q *Queue) error {

	// We only need queue information after declaring it
	_, err := c.channel.QueueDeclare(
		q.name,
		q.durable,
		q.deleteWhenUnUsed,
		q.exclusive,
		q.noWait,
		q.params,
	)

	if err != nil {
		log.Println("Failed to declare queue")
		return errors.New("Failed to declare queue")
	}
	log.Println("Declared queue")
	return nil
}

func (c *AmqpConnection) declareExchange(e *Exchange) error {

	// We only need queue information after declaring it
	err := c.channel.ExchangeDeclare(
		e.name,
		e.exchangeType,
		e.durable,
		e.deleteWhenUnUsed,
		e.exclusive,
		e.noWait,
		e.params,
	)

	if err != nil {
		log.Println("Failed to declare exchange")
		return errors.New("Failed to declare exchange")
	}

	log.Println("Declared exchange")
	return nil
}

// Binds the queue to an exchange and creates a Bindind object
func (c *AmqpConnection) bind(name, routingKey string, e *Exchange, q *Queue) (*Binding, error) {
	err := c.channel.QueueBind(q.name, routingKey, e.name, q.noWait, nil)
	if err != nil {
		log.Println("Failed to Bind queue to exchange")
		return nil, errors.New("Failed to Bind queue to exchange")
	}

	b := &Binding{
		name:       name,
		routingKey: routingKey,
		queue:      q,
		exchange:   e,
	}

	// This way we could obtain all the bindings of each exchange
	e.bindings = append(e.bindings, b)

	log.Println("Binded exchange with channel")
	return b, nil

}

// Converts an amqp message to a custom message
func (c *AmqpConnection) convertMessage(m *amqp.Delivery) *Message {
	return &Message{
		ContentType: m.ContentType,
		Body:        m.Body,
		Original:    m,
	}
}

func (c *AmqpConnection) Ack(m *Message) error {
	d := m.Original.(*amqp.Delivery)
	return d.Ack(false)
}

// Aux types
type Queue struct {
	name             string
	durable          bool
	deleteWhenUnUsed bool
	exclusive        bool
	noWait           bool
	params           amqp.Table
}

type Exchange struct {
	name             string
	exchangeType     string
	durable          bool
	deleteWhenUnUsed bool
	exclusive        bool
	noWait           bool
	params           amqp.Table
	bindings         []*Binding //For now use one only
}

type Binding struct {
	name       string
	routingKey string
	queue      *Queue
	exchange   *Exchange
}
<|endoftext|>


<commit_before>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 auth

import (
	"github.com/jacobsa/aws"
	"github.com/jacobsa/aws/s3/http"
	. "github.com/jacobsa/ogletest"
	"testing"
)

func TestSigner(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

type SignerTest struct {}

func init() { RegisterTestSuite(&SignerTest{}) }

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *SignerTest) CallsFunction() {
	// Function
	var stsArg *http.Request
	sts := func(r *http.Request)(string, error) { stsArg = r; return "", nil }

	// Signer
	signer, err := newSigner(sts, aws.AccessKey{})
	AssertEq(nil, err)

	// Call
	req := &http.Request{}
	signer.Sign(req)

	ExpectEq(req, stsArg)
}

func (t *SignerTest) FunctionReturnsError() {
	ExpectEq("TODO", "")
}

func (t *SignerTest) FunctionReturnsString() {
	ExpectEq("TODO", "")
}

func (t *SignerTest) GoldenTests() {
	ExpectEq("TODO", "")
}
<commit_msg>SignerTest.FunctionReturnsError<commit_after>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 auth

import (
	"errors"
	"github.com/jacobsa/aws"
	"github.com/jacobsa/aws/s3/http"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
	"testing"
)

func TestSigner(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

type SignerTest struct {}

func init() { RegisterTestSuite(&SignerTest{}) }

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *SignerTest) CallsFunction() {
	// Function
	var stsArg *http.Request
	sts := func(r *http.Request)(string, error) { stsArg = r; return "", nil }

	// Signer
	signer, err := newSigner(sts, aws.AccessKey{})
	AssertEq(nil, err)

	// Call
	req := &http.Request{}
	signer.Sign(req)

	ExpectEq(req, stsArg)
}

func (t *SignerTest) FunctionReturnsError() {
	// Function
	sts := func(r *http.Request)(string, error) { return "", errors.New("taco") }

	// Signer
	signer, err := newSigner(sts, aws.AccessKey{})
	AssertEq(nil, err)

	// Call
	err = signer.Sign(&http.Request{})

	ExpectThat(err, Error(HasSubstr("Sign")))
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *SignerTest) FunctionReturnsString() {
	ExpectEq("TODO", "")
}

func (t *SignerTest) GoldenTests() {
	ExpectEq("TODO", "")
}
<|endoftext|>