<commit_before>package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/gonuts/commander"
	"github.com/gonuts/flag"
)

func hwaf_make_cmd_init() *commander.Command {
	cmd := &commander.Command{
		Run:       hwaf_run_cmd_init,
		UsageLine: "init [options] <workarea>",
		Short:     "initialize a new workarea",
		Long: `
init initializes a new workarea.

ex:
 $ hwaf init
 $ hwaf init .
 $ hwaf init my-work-area
`,
		Flag: *flag.NewFlagSet("hwaf-init", flag.ExitOnError),
	}
	cmd.Flag.Bool("q", true, "only print error and warning messages, all other output will be suppressed")
	cmd.Flag.String("name", "", "workarea/project name (default: directory-name)")
	return cmd
}

func hwaf_run_cmd_init(cmd *commander.Command, args []string) {
	var err error
	n := "hwaf-" + cmd.Name()
	dirname := ""

	switch len(args) {
	case 0:
		dirname = "."
	case 1:
		dirname = args[0]
	default:
		err = fmt.Errorf("%s: you need to give a directory name", n)
		handle_err(err)
	}

	dirname = os.ExpandEnv(dirname)
	dirname = filepath.Clean(dirname)

	quiet := cmd.Flag.Lookup("q").Value.Get().(bool)
	proj_name := cmd.Flag.Lookup("name").Value.Get().(string)
	if proj_name == "" {
		proj_name = filepath.Base(dirname)
	}
	if proj_name == "." {
		pwd, err := os.Getwd()
		handle_err(err)
		proj_name = filepath.Base(pwd)
	}

	if !quiet {
		fmt.Printf("%s: creating workarea [%s]...\n", n, dirname)
	}

	if !path_exists(dirname) {
		err = os.MkdirAll(dirname, 0700)
		handle_err(err)
	}

	pwd, err := os.Getwd()
	handle_err(err)
	defer os.Chdir(pwd)

	err = os.Chdir(dirname)
	handle_err(err)

	// init a git repository in dirname
	if !quiet {
		fmt.Printf("%s: initialize git workarea repository...\n", n)
	}
	git := exec.Command("git", "init", ".")
	if !quiet {
		git.Stdout = os.Stdout
		git.Stderr = os.Stderr
	}
	err = git.Run()
	handle_err(err)

	// add hep-waf-tools
	if !quiet {
		fmt.Printf("%s: add .hwaf/tools...\n", n)
	}
	hwaf_tools_dir := filepath.Join("${HOME}", ".config", "hwaf", "tools")
	hwaf_tools_dir = os.ExpandEnv(hwaf_tools_dir)
	if !path_exists(hwaf_tools_dir) {
		// first try the r/w url...
		git = exec.Command(
			"git", "clone", "git@github.com:mana-fwk/hep-waftools",
			hwaf_tools_dir,
		)
		if !quiet {
			git.Stdout = os.Stdout
			git.Stderr = os.Stderr
		}

		if git.Run() != nil {
			git := exec.Command(
				"git", "clone", "git://github.com/mana-fwk/hep-waftools",
				hwaf_tools_dir,
			)
			if !quiet {
				git.Stdout = os.Stdout
				git.Stderr = os.Stderr
			}
			err = git.Run()
			handle_err(err)
		}
	}
	if !path_exists(".hwaf") {
		err = os.MkdirAll(".hwaf", 0700)
		handle_err(err)
	}
	if path_exists(".hwaf/tools") {
		err = os.RemoveAll(".hwaf/tools")
		handle_err(err)
	}
	err = os.Symlink(hwaf_tools_dir, ".hwaf/tools")
	handle_err(err)

	git = exec.Command("git", "add", ".hwaf/tools")
	if !quiet {
		git.Stdout = os.Stdout
		git.Stderr = os.Stderr
	}
	err = git.Run()
	handle_err(err)

	// add template wscript
	if !quiet {
		fmt.Printf("%s: add top-level wscript...\n", n)
	}

	if !path_exists("wscript") {
		wscript_tmpl, err := os.Open(".hwaf/tools/hwaf-wscript")
		handle_err(err)
		defer wscript_tmpl.Close()

		wscript_b, err := ioutil.ReadAll(wscript_tmpl)
		handle_err(err)

		// replace 'hwaf-workarea' with workarea name
		wscript_s := strings.Replace(
			string(wscript_b),
			"APPNAME = 'hwaf-workarea'",
			fmt.Sprintf("APPNAME = '%s'", proj_name),
			-1)

		wscript, err := os.Create("wscript")
		handle_err(err)
		defer wscript.Close()

		_, err = io.WriteString(wscript, wscript_s)
		handle_err(err)
		handle_err(wscript.Sync())
		handle_err(wscript.Close())
	}

	git = exec.Command("git", "add", "wscript")
	if !quiet {
		git.Stdout = os.Stdout
		git.Stderr = os.Stderr
	}
	err = git.Run()
	handle_err(err)

	// create 'src' directory
	if !path_exists("src") {
		err = os.MkdirAll("src", 0700)
		handle_err(err)
	}

	// add a default .gitignore
	gitignore_tmpl, err := os.Open(".hwaf/tools/.gitignore")
	handle_err(err)
	defer gitignore_tmpl.Close()

	gitignore, err := os.Create(".gitignore")
	handle_err(err)
	defer gitignore.Close()

	_, err = io.Copy(gitignore, gitignore_tmpl)
	handle_err(err)
	handle_err(gitignore.Sync())
	handle_err(gitignore.Close())

	git = exec.Command("git", "add", ".gitignore")
	if !quiet {
		git.Stdout = os.Stdout
		git.Stderr = os.Stderr
	}
	err = git.Run()
	handle_err(err)

	// check whether we need to commit
	err = exec.Command("git", "diff", "--exit-code", "--quiet", "HEAD").Run()
	if err != nil {
		// commit
		if !quiet {
			fmt.Printf("%s: commit workarea...\n", n)
		}
		git = exec.Command(
			"git", "commit", "-m",
			fmt.Sprintf("init hwaf project [%s]", proj_name),
		)
		if !quiet {
			git.Stdout = os.Stdout
			git.Stderr = os.Stderr
		}
		err = git.Run()
		handle_err(err)
	}

	if !quiet {
		fmt.Printf("%s: creating workarea [%s]... [ok]\n", n, dirname)
	}
}

// EOF
<commit_msg>cmd-init: use hwaf-tools from HWAF_ROOT if available. fallback to git-clone<commit_after>package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/gonuts/commander"
	"github.com/gonuts/flag"
)

func hwaf_make_cmd_init() *commander.Command {
	cmd := &commander.Command{
		Run:       hwaf_run_cmd_init,
		UsageLine: "init [options] <workarea>",
		Short:     "initialize a new workarea",
		Long: `
init initializes a new workarea.

ex:
 $ hwaf init
 $ hwaf init .
 $ hwaf init my-work-area
`,
		Flag: *flag.NewFlagSet("hwaf-init", flag.ExitOnError),
	}
	cmd.Flag.Bool("q", true, "only print error and warning messages, all other output will be suppressed")
	cmd.Flag.String("name", "", "workarea/project name (default: directory-name)")
	return cmd
}

func hwaf_run_cmd_init(cmd *commander.Command, args []string) {
	var err error
	n := "hwaf-" + cmd.Name()
	dirname := ""

	switch len(args) {
	case 0:
		dirname = "."
	case 1:
		dirname = args[0]
	default:
		err = fmt.Errorf("%s: you need to give a directory name", n)
		handle_err(err)
	}

	dirname = os.ExpandEnv(dirname)
	dirname = filepath.Clean(dirname)

	quiet := cmd.Flag.Lookup("q").Value.Get().(bool)
	proj_name := cmd.Flag.Lookup("name").Value.Get().(string)
	if proj_name == "" {
		proj_name = filepath.Base(dirname)
	}
	if proj_name == "." {
		pwd, err := os.Getwd()
		handle_err(err)
		proj_name = filepath.Base(pwd)
	}

	if !quiet {
		fmt.Printf("%s: creating workarea [%s]...\n", n, dirname)
	}

	if !path_exists(dirname) {
		err = os.MkdirAll(dirname, 0700)
		handle_err(err)
	}

	pwd, err := os.Getwd()
	handle_err(err)
	defer os.Chdir(pwd)

	err = os.Chdir(dirname)
	handle_err(err)

	// init a git repository in dirname
	if !quiet {
		fmt.Printf("%s: initialize git workarea repository...\n", n)
	}
	git := exec.Command("git", "init", ".")
	if !quiet {
		git.Stdout = os.Stdout
		git.Stderr = os.Stderr
	}
	err = git.Run()
	handle_err(err)

	// add hep-waf-tools
	if !quiet {
		fmt.Printf("%s: add .hwaf/tools...\n", n)
	}
	hwaf_tools_dir := ""
	if g_ctx.Root != "" {
		hwaf_tools_dir = filepath.Join(g_ctx.Root, "share", "hwaf", "tools")
	} else {
		hwaf_tools_dir = filepath.Join("${HOME}", ".config", "hwaf", "tools")
	}
	hwaf_tools_dir = os.ExpandEnv(hwaf_tools_dir)
	if !path_exists(hwaf_tools_dir) {
		// first try the r/w url...
		git = exec.Command(
			"git", "clone", "git@github.com:mana-fwk/hep-waftools",
			hwaf_tools_dir,
		)
		if !quiet {
			git.Stdout = os.Stdout
			git.Stderr = os.Stderr
		}

		if git.Run() != nil {
			git := exec.Command(
				"git", "clone", "git://github.com/mana-fwk/hep-waftools",
				hwaf_tools_dir,
			)
			if !quiet {
				git.Stdout = os.Stdout
				git.Stderr = os.Stderr
			}
			err = git.Run()
			handle_err(err)
		}
	}
	if !path_exists(".hwaf") {
		err = os.MkdirAll(".hwaf", 0700)
		handle_err(err)
	}
	if path_exists(".hwaf/tools") {
		err = os.RemoveAll(".hwaf/tools")
		handle_err(err)
	}
	err = os.Symlink(hwaf_tools_dir, ".hwaf/tools")
	handle_err(err)

	git = exec.Command("git", "add", ".hwaf/tools")
	if !quiet {
		git.Stdout = os.Stdout
		git.Stderr = os.Stderr
	}
	err = git.Run()
	handle_err(err)

	// add template wscript
	if !quiet {
		fmt.Printf("%s: add top-level wscript...\n", n)
	}

	if !path_exists("wscript") {
		wscript_tmpl, err := os.Open(".hwaf/tools/hwaf-wscript")
		handle_err(err)
		defer wscript_tmpl.Close()

		wscript_b, err := ioutil.ReadAll(wscript_tmpl)
		handle_err(err)

		// replace 'hwaf-workarea' with workarea name
		wscript_s := strings.Replace(
			string(wscript_b),
			"APPNAME = 'hwaf-workarea'",
			fmt.Sprintf("APPNAME = '%s'", proj_name),
			-1)

		wscript, err := os.Create("wscript")
		handle_err(err)
		defer wscript.Close()

		_, err = io.WriteString(wscript, wscript_s)
		handle_err(err)
		handle_err(wscript.Sync())
		handle_err(wscript.Close())
	}

	git = exec.Command("git", "add", "wscript")
	if !quiet {
		git.Stdout = os.Stdout
		git.Stderr = os.Stderr
	}
	err = git.Run()
	handle_err(err)

	// create 'src' directory
	if !path_exists("src") {
		err = os.MkdirAll("src", 0700)
		handle_err(err)
	}

	// add a default .gitignore
	gitignore_tmpl, err := os.Open(".hwaf/tools/.gitignore")
	handle_err(err)
	defer gitignore_tmpl.Close()

	gitignore, err := os.Create(".gitignore")
	handle_err(err)
	defer gitignore.Close()

	_, err = io.Copy(gitignore, gitignore_tmpl)
	handle_err(err)
	handle_err(gitignore.Sync())
	handle_err(gitignore.Close())

	git = exec.Command("git", "add", ".gitignore")
	if !quiet {
		git.Stdout = os.Stdout
		git.Stderr = os.Stderr
	}
	err = git.Run()
	handle_err(err)

	// check whether we need to commit
	err = exec.Command("git", "diff", "--exit-code", "--quiet", "HEAD").Run()
	if err != nil {
		// commit
		if !quiet {
			fmt.Printf("%s: commit workarea...\n", n)
		}
		git = exec.Command(
			"git", "commit", "-m",
			fmt.Sprintf("init hwaf project [%s]", proj_name),
		)
		if !quiet {
			git.Stdout = os.Stdout
			git.Stderr = os.Stderr
		}
		err = git.Run()
		handle_err(err)
	}

	if !quiet {
		fmt.Printf("%s: creating workarea [%s]... [ok]\n", n, dirname)
	}
}

// EOF
<|endoftext|>


<commit_before>// Copyright 2014 Martin Angers and Contributors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package fetchbot

import (
	"encoding/base64"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"net/url"
	"sort"
	"strings"
	"testing"
)

type basicAuthCmd struct {
	*Cmd
	user, pwd string
}

func (ba *basicAuthCmd) BasicAuth() (string, string) {
	return ba.user, ba.pwd
}

func TestBasicAuth(t *testing.T) {
	creds := base64.StdEncoding.EncodeToString([]byte("me:you"))
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		auth := req.Header.Get("Authorization")
		if auth != "Basic "+creds {
			w.Header().Set("WWW-Authenticate", "Basic realm=\"Authorization Required\"")
			http.Error(w, "Unauthorized", http.StatusUnauthorized)
			return
		}
		w.Write([]byte("ok"))
	}))
	defer srv.Close()
	cases := []struct {
		cmd    Command
		status int
	}{
		0: {
			&basicAuthCmd{&Cmd{U: mustParse(t, srv.URL+"/a"), M: "GET"}, "me", "you"},
			http.StatusOK,
		},
		1: {
			&Cmd{U: mustParse(t, srv.URL+"/b"), M: "GET"},
			http.StatusUnauthorized,
		},
		2: {
			&basicAuthCmd{&Cmd{U: mustParse(t, srv.URL+"/c"), M: "GET"}, "some", "other"},
			http.StatusUnauthorized,
		},
		3: {
			&readerCmd{&Cmd{U: mustParse(t, srv.URL+"/d"), M: "POST"},
				strings.NewReader("a")},
			http.StatusUnauthorized,
		},
		4: {
			&valuesCmd{&Cmd{U: mustParse(t, srv.URL+"/e"), M: "POST"},
				url.Values{"k": {"v"}}},
			http.StatusUnauthorized,
		},
	}
	sh := &spyHandler{}
	f := New(sh)
	f.CrawlDelay = 0
	q := f.Start()
	for i, c := range cases {
		if err := q.Send(c.cmd); err != nil {
			t.Errorf("%d: error sending command: %s", i, err)
		}
	}
	q.Close()
	var urls []string
	for i, c := range cases {
		urls = append(urls, c.cmd.URL().String())
		if st := sh.StatusFor(c.cmd.URL().String()); st != c.status {
			t.Errorf("%d: expected status %d, got %d", i, c.status, st)
		}
	}
	if !sh.CalledWithExactly(urls...) {
		t.Error("expected handler to be called for all cases")
	}
	if cnt := sh.Errors(); cnt > 0 {
		t.Errorf("expected no error, got %d", cnt)
	}
}

type readerCmd struct {
	*Cmd
	r io.Reader
}

func (rc *readerCmd) Reader() io.Reader {
	return rc.r
}

type valuesCmd struct {
	*Cmd
	vals url.Values
}

func (vc *valuesCmd) Values() url.Values {
	return vc.vals
}

type cookiesCmd struct {
	*Cmd
	cooks []*http.Cookie
}

func (cc *cookiesCmd) Cookies() []*http.Cookie {
	return cc.cooks
}

func TestBody(t *testing.T) {
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		cooks := req.Cookies()
		if len(cooks) == 0 {
			b, err := ioutil.ReadAll(req.Body)
			if err != nil {
				w.WriteHeader(http.StatusInternalServerError)
				w.Write([]byte(err.Error()))
				return
			}
			w.Write(b)
		} else {
			for i, c := range cooks {
				if i > 0 {
					w.Write([]byte{'&'})
				}
				w.Write([]byte(c.Name))
			}
		}
	}))
	defer srv.Close()
	cases := []struct {
		cmd  Command
		body string
	}{
		0: {
			&readerCmd{&Cmd{U: mustParse(t, srv.URL+"/a"), M: "POST"},
				strings.NewReader("a")},
			"a",
		},
		1: {
			&valuesCmd{&Cmd{U: mustParse(t, srv.URL+"/b"), M: "POST"},
				url.Values{"k": {"v"}}},
			"k=v",
		},
		2: {
			&Cmd{U: mustParse(t, srv.URL+"/c"), M: "POST"},
			"",
		},
		3: {
			&basicAuthCmd{&Cmd{U: mustParse(t, srv.URL+"/d"), M: "POST"}, "me", "you"},
			"",
		},
		4: {
			&cookiesCmd{&Cmd{U: mustParse(t, srv.URL+"/e"), M: "GET"},
				[]*http.Cookie{&http.Cookie{Name: "e"}}},
			"e",
		},
		5: {
			&cookiesCmd{&Cmd{U: mustParse(t, srv.URL+"/f"), M: "GET"},
				[]*http.Cookie{&http.Cookie{Name: "f1"}, &http.Cookie{Name: "f2"}}},
			"f1&f2",
		},
	}
	sh := &spyHandler{}
	f := New(sh)
	f.CrawlDelay = 0
	q := f.Start()
	for i, c := range cases {
		if err := q.Send(c.cmd); err != nil {
			t.Errorf("%d: error sending command: %s", i, err)
		}
	}
	q.Close()
	var urls []string
	for i, c := range cases {
		urls = append(urls, c.cmd.URL().String())
		if b := sh.BodyFor(c.cmd.URL().String()); b != c.body {
			t.Errorf("%d: expected body '%s', got '%s'", i, c.body, b)
		}
	}
	if !sh.CalledWithExactly(urls...) {
		t.Error("expected handler to be called for all cases")
	}
	if cnt := sh.Errors(); cnt > 0 {
		t.Errorf("expected no error, got %d", cnt)
	}
}

type headerCmd struct {
	*Cmd
	hdr http.Header
}

func (hc *headerCmd) Header() http.Header {
	return hc.hdr
}

func TestHeader(t *testing.T) {
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		// Write headers in lexical order so that result is predictable
		keys := make([]string, 0, len(req.Header))
		for k := range req.Header {
			if len(k) == 1 {
				keys = append(keys, k)
			}
		}
		sort.Strings(keys)
		for _, k := range keys {
			w.Write([]byte(fmt.Sprintf("%s:%s\n", k, req.Header[k][0])))
		}
	}))
	defer srv.Close()
	cases := []struct {
		cmd  Command
		body string
	}{
		0: {
			&headerCmd{&Cmd{U: mustParse(t, srv.URL+"/a"), M: "GET"},
				http.Header{"A": {"a"}}},
			"A:a\n",
		},
		1: {
			&Cmd{U: mustParse(t, srv.URL+"/b"), M: "GET"},
			"",
		},
		2: {
			&headerCmd{&Cmd{U: mustParse(t, srv.URL+"/c"), M: "GET"},
				http.Header{"C": {"c"}, "D": {"d"}}},
			"C:c\nD:d\n",
		},
	}
	sh := &spyHandler{}
	f := New(sh)
	f.CrawlDelay = 0
	q := f.Start()
	for i, c := range cases {
		if err := q.Send(c.cmd); err != nil {
			t.Errorf("%d: error sending command: %s", i, err)
		}
	}
	q.Close()
	var urls []string
	for i, c := range cases {
		urls = append(urls, c.cmd.URL().String())
		if b := sh.BodyFor(c.cmd.URL().String()); b != c.body {
			t.Errorf("%d: expected body '%s', got '%s'", i, c.body, b)
		}
	}
	if !sh.CalledWithExactly(urls...) {
		t.Error("expected handler to be called for all cases")
	}
	if cnt := sh.Errors(); cnt > 0 {
		t.Errorf("expected no error, got %d", cnt)
	}
}

type fullCmd struct {
	*Cmd
	user, pwd string
	r         io.Reader
	vals      url.Values
	cooks     []*http.Cookie
	hdr       http.Header
}

func (f *fullCmd) BasicAuth() (string, string) {
	return f.user, f.pwd
}

func (f *fullCmd) Reader() io.Reader {
	return f.r
}

func (f *fullCmd) Values() url.Values {
	return f.vals
}

func (f *fullCmd) Cookies() []*http.Cookie {
	return f.cooks
}

func (f *fullCmd) Header() http.Header {
	return f.hdr
}

func TestFullCmd(t *testing.T) {
	creds := base64.StdEncoding.EncodeToString([]byte("me:you"))
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		// Basic auth
		auth := req.Header.Get("Authorization")
		if auth != "Basic "+creds {
			w.Header().Set("WWW-Authenticate", "Basic realm=\"Authorization Required\"")
			http.Error(w, "Unauthorized", http.StatusUnauthorized)
			return
		}
		// Cookies
		for i, c := range req.Cookies() {
			if i > 0 {
				w.Write([]byte{'&'})
			}
			w.Write([]byte(c.Name))
		}
		// Header
		for k, v := range req.Header {
			if len(k) == 1 {
				w.Write([]byte(fmt.Sprintf("%s:%s\n", k, v[0])))
			}
		}
		// Body
		b, err := ioutil.ReadAll(req.Body)
		if err != nil {
			t.Fatal(err)
		}
		w.Write(b)
	}))
	defer srv.Close()

	sh := &spyHandler{}
	f := New(sh)
	f.CrawlDelay = 0
	q := f.Start()
	cmd := &fullCmd{
		&Cmd{U: mustParse(t, srv.URL+"/a"), M: "POST"},
		"me", "you",
		strings.NewReader("body"),
		url.Values{"ignored": {"val"}},
		[]*http.Cookie{&http.Cookie{Name: "a"}},
		http.Header{"A": {"a"}},
	}
	if err := q.Send(cmd); err != nil {
		t.Fatal(err)
	}
	q.Close()
	// Assert 200 status
	if st := sh.StatusFor(cmd.URL().String()); st != 200 {
		t.Errorf("expected status %d, got %d", 200, st)
	}
	// Assert body (Cookies + Header)
	exp := "aA:a\nbody"
	if b := sh.BodyFor(cmd.URL().String()); b != exp {
		t.Errorf("expected body '%s', got '%s'", exp, b)
	}
}

func mustParse(t *testing.T, raw string) *url.URL {
	parsed, err := url.Parse(raw)
	if err != nil {
		t.Fatal(err)
	}
	return parsed
}
<commit_msg>test HandlerCmd behaviour<commit_after>// Copyright 2014 Martin Angers and Contributors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package fetchbot

import (
	"encoding/base64"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"net/url"
	"sort"
	"strings"
	"sync/atomic"
	"testing"
)

type basicAuthCmd struct {
	*Cmd
	user, pwd string
}

func (ba *basicAuthCmd) BasicAuth() (string, string) {
	return ba.user, ba.pwd
}

func TestBasicAuth(t *testing.T) {
	creds := base64.StdEncoding.EncodeToString([]byte("me:you"))
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		auth := req.Header.Get("Authorization")
		if auth != "Basic "+creds {
			w.Header().Set("WWW-Authenticate", "Basic realm=\"Authorization Required\"")
			http.Error(w, "Unauthorized", http.StatusUnauthorized)
			return
		}
		w.Write([]byte("ok"))
	}))
	defer srv.Close()
	cases := []struct {
		cmd    Command
		status int
	}{
		0: {
			&basicAuthCmd{&Cmd{U: mustParse(t, srv.URL+"/a"), M: "GET"}, "me", "you"},
			http.StatusOK,
		},
		1: {
			&Cmd{U: mustParse(t, srv.URL+"/b"), M: "GET"},
			http.StatusUnauthorized,
		},
		2: {
			&basicAuthCmd{&Cmd{U: mustParse(t, srv.URL+"/c"), M: "GET"}, "some", "other"},
			http.StatusUnauthorized,
		},
		3: {
			&readerCmd{&Cmd{U: mustParse(t, srv.URL+"/d"), M: "POST"},
				strings.NewReader("a")},
			http.StatusUnauthorized,
		},
		4: {
			&valuesCmd{&Cmd{U: mustParse(t, srv.URL+"/e"), M: "POST"},
				url.Values{"k": {"v"}}},
			http.StatusUnauthorized,
		},
	}
	sh := &spyHandler{}
	f := New(sh)
	f.CrawlDelay = 0
	q := f.Start()
	for i, c := range cases {
		if err := q.Send(c.cmd); err != nil {
			t.Errorf("%d: error sending command: %s", i, err)
		}
	}
	q.Close()
	var urls []string
	for i, c := range cases {
		urls = append(urls, c.cmd.URL().String())
		if st := sh.StatusFor(c.cmd.URL().String()); st != c.status {
			t.Errorf("%d: expected status %d, got %d", i, c.status, st)
		}
	}
	if !sh.CalledWithExactly(urls...) {
		t.Error("expected handler to be called for all cases")
	}
	if cnt := sh.Errors(); cnt > 0 {
		t.Errorf("expected no error, got %d", cnt)
	}
}

type readerCmd struct {
	*Cmd
	r io.Reader
}

func (rc *readerCmd) Reader() io.Reader {
	return rc.r
}

type valuesCmd struct {
	*Cmd
	vals url.Values
}

func (vc *valuesCmd) Values() url.Values {
	return vc.vals
}

type cookiesCmd struct {
	*Cmd
	cooks []*http.Cookie
}

func (cc *cookiesCmd) Cookies() []*http.Cookie {
	return cc.cooks
}

func TestBody(t *testing.T) {
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		cooks := req.Cookies()
		if len(cooks) == 0 {
			b, err := ioutil.ReadAll(req.Body)
			if err != nil {
				w.WriteHeader(http.StatusInternalServerError)
				w.Write([]byte(err.Error()))
				return
			}
			w.Write(b)
		} else {
			for i, c := range cooks {
				if i > 0 {
					w.Write([]byte{'&'})
				}
				w.Write([]byte(c.Name))
			}
		}
	}))
	defer srv.Close()
	cases := []struct {
		cmd  Command
		body string
	}{
		0: {
			&readerCmd{&Cmd{U: mustParse(t, srv.URL+"/a"), M: "POST"},
				strings.NewReader("a")},
			"a",
		},
		1: {
			&valuesCmd{&Cmd{U: mustParse(t, srv.URL+"/b"), M: "POST"},
				url.Values{"k": {"v"}}},
			"k=v",
		},
		2: {
			&Cmd{U: mustParse(t, srv.URL+"/c"), M: "POST"},
			"",
		},
		3: {
			&basicAuthCmd{&Cmd{U: mustParse(t, srv.URL+"/d"), M: "POST"}, "me", "you"},
			"",
		},
		4: {
			&cookiesCmd{&Cmd{U: mustParse(t, srv.URL+"/e"), M: "GET"},
				[]*http.Cookie{&http.Cookie{Name: "e"}}},
			"e",
		},
		5: {
			&cookiesCmd{&Cmd{U: mustParse(t, srv.URL+"/f"), M: "GET"},
				[]*http.Cookie{&http.Cookie{Name: "f1"}, &http.Cookie{Name: "f2"}}},
			"f1&f2",
		},
	}
	sh := &spyHandler{}
	f := New(sh)
	f.CrawlDelay = 0
	q := f.Start()
	for i, c := range cases {
		if err := q.Send(c.cmd); err != nil {
			t.Errorf("%d: error sending command: %s", i, err)
		}
	}
	q.Close()
	var urls []string
	for i, c := range cases {
		urls = append(urls, c.cmd.URL().String())
		if b := sh.BodyFor(c.cmd.URL().String()); b != c.body {
			t.Errorf("%d: expected body '%s', got '%s'", i, c.body, b)
		}
	}
	if !sh.CalledWithExactly(urls...) {
		t.Error("expected handler to be called for all cases")
	}
	if cnt := sh.Errors(); cnt > 0 {
		t.Errorf("expected no error, got %d", cnt)
	}
}

type headerCmd struct {
	*Cmd
	hdr http.Header
}

func (hc *headerCmd) Header() http.Header {
	return hc.hdr
}

func TestHeader(t *testing.T) {
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		// Write headers in lexical order so that result is predictable
		keys := make([]string, 0, len(req.Header))
		for k := range req.Header {
			if len(k) == 1 {
				keys = append(keys, k)
			}
		}
		sort.Strings(keys)
		for _, k := range keys {
			w.Write([]byte(fmt.Sprintf("%s:%s\n", k, req.Header[k][0])))
		}
	}))
	defer srv.Close()
	cases := []struct {
		cmd  Command
		body string
	}{
		0: {
			&headerCmd{&Cmd{U: mustParse(t, srv.URL+"/a"), M: "GET"},
				http.Header{"A": {"a"}}},
			"A:a\n",
		},
		1: {
			&Cmd{U: mustParse(t, srv.URL+"/b"), M: "GET"},
			"",
		},
		2: {
			&headerCmd{&Cmd{U: mustParse(t, srv.URL+"/c"), M: "GET"},
				http.Header{"C": {"c"}, "D": {"d"}}},
			"C:c\nD:d\n",
		},
	}
	sh := &spyHandler{}
	f := New(sh)
	f.CrawlDelay = 0
	q := f.Start()
	for i, c := range cases {
		if err := q.Send(c.cmd); err != nil {
			t.Errorf("%d: error sending command: %s", i, err)
		}
	}
	q.Close()
	var urls []string
	for i, c := range cases {
		urls = append(urls, c.cmd.URL().String())
		if b := sh.BodyFor(c.cmd.URL().String()); b != c.body {
			t.Errorf("%d: expected body '%s', got '%s'", i, c.body, b)
		}
	}
	if !sh.CalledWithExactly(urls...) {
		t.Error("expected handler to be called for all cases")
	}
	if cnt := sh.Errors(); cnt > 0 {
		t.Errorf("expected no error, got %d", cnt)
	}
}

type fullCmd struct {
	*Cmd
	user, pwd string
	r         io.Reader
	vals      url.Values
	cooks     []*http.Cookie
	hdr       http.Header
}

func (f *fullCmd) BasicAuth() (string, string) {
	return f.user, f.pwd
}

func (f *fullCmd) Reader() io.Reader {
	return f.r
}

func (f *fullCmd) Values() url.Values {
	return f.vals
}

func (f *fullCmd) Cookies() []*http.Cookie {
	return f.cooks
}

func (f *fullCmd) Header() http.Header {
	return f.hdr
}

func TestFullCmd(t *testing.T) {
	creds := base64.StdEncoding.EncodeToString([]byte("me:you"))
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		// Basic auth
		auth := req.Header.Get("Authorization")
		if auth != "Basic "+creds {
			w.Header().Set("WWW-Authenticate", "Basic realm=\"Authorization Required\"")
			http.Error(w, "Unauthorized", http.StatusUnauthorized)
			return
		}
		// Cookies
		for i, c := range req.Cookies() {
			if i > 0 {
				w.Write([]byte{'&'})
			}
			w.Write([]byte(c.Name))
		}
		// Header
		for k, v := range req.Header {
			if len(k) == 1 {
				w.Write([]byte(fmt.Sprintf("%s:%s\n", k, v[0])))
			}
		}
		// Body
		b, err := ioutil.ReadAll(req.Body)
		if err != nil {
			t.Fatal(err)
		}
		w.Write(b)
	}))
	defer srv.Close()

	sh := &spyHandler{}
	f := New(sh)
	f.CrawlDelay = 0
	q := f.Start()
	cmd := &fullCmd{
		&Cmd{U: mustParse(t, srv.URL+"/a"), M: "POST"},
		"me", "you",
		strings.NewReader("body"),
		url.Values{"ignored": {"val"}},
		[]*http.Cookie{&http.Cookie{Name: "a"}},
		http.Header{"A": {"a"}},
	}
	if err := q.Send(cmd); err != nil {
		t.Fatal(err)
	}
	q.Close()
	// Assert 200 status
	if st := sh.StatusFor(cmd.URL().String()); st != 200 {
		t.Errorf("expected status %d, got %d", 200, st)
	}
	// Assert body (Cookies + Header)
	exp := "aA:a\nbody"
	if b := sh.BodyFor(cmd.URL().String()); b != exp {
		t.Errorf("expected body '%s', got '%s'", exp, b)
	}
}

func TestHandlerCmd(t *testing.T) {
	var result int32
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {}))
	defer srv.Close()

	cases := []struct {
		cmd  Command
		want int32
	}{
		0: {
			mustCmd(NewHandlerCmd("GET", srv.URL+"/a", func(ctx *Context, res *http.Response, err error) {
				atomic.AddInt32(&result, 1)
			})), 1,
		},
		1: {
			&Cmd{U: mustParse(t, srv.URL+"/b"), M: "GET"}, -1,
		},
	}

	f := New(HandlerFunc(func(ctx *Context, res *http.Response, err error) {
		atomic.AddInt32(&result, -1)
	}))
	f.CrawlDelay = 0

	for i, c := range cases {
		result = 0
		q := f.Start()
		if err := q.Send(c.cmd); err != nil {
			t.Errorf("%d: error sending command: %s", i, err)
		}
		q.Close()

		if result != c.want {
			t.Errorf("%d: want %d, got %d", i, c.want, result)
		}
	}
}

func mustCmd(cmd Command, err error) Command {
	if err != nil {
		panic(err)
	}
	return cmd
}

func mustParse(t *testing.T, raw string) *url.URL {
	parsed, err := url.Parse(raw)
	if err != nil {
		t.Fatal(err)
	}
	return parsed
}
<|endoftext|>


<commit_before>// Copyright © 2016 Aaron Longwell
//
// Use of this source code is governed by an MIT license.
// Details in the LICENSE file.

package trello

import (
	"testing"
	"time"
)

func TestCreateBoard(t *testing.T) {
	c := testClient()
	c.BaseURL = mockResponse("boards", "AkFGHS12.json").URL

	board := Board{
		Name: "Test Board Create",
	}

	err := c.CreateBoard(&board, Defaults())
	if err != nil {
		t.Error(err)
	}

	if board.ID != "5c602cf77061a8169a69deb5" {
		t.Errorf("Expected board to pick up an ID. Instead got '%s'.", board.ID)
	}
}

func TestDeleteBoard(t *testing.T) {
	c := testClient()
	c.BaseURL = mockResponse("boards", "deleted.json").URL

	board := Board{
		ID:   "5c602cf77061a8169a69deb5",
		Name: "Test Board Create",
	}
	board.client = c

	err := board.Delete(Defaults())
	if err != nil {
		t.Error(err)
	}
}

func TestBoardCreatedAt(t *testing.T) {
	b := Board{ID: "4d5ea62fd76aa1136000000c"}
	ts := b.CreatedAt()
	if ts.IsZero() {
		t.Error("Time shouldn't be zero.")
	}
	if ts.Unix() != 1298048559 {
		t.Errorf("Incorrect CreatedAt() time: '%s'.", ts.Format(time.RFC3339))
	}
}

func TestGetBoard(t *testing.T) {
	board := testBoard(t)
	if board.Name != "Trello Public API" {
		t.Errorf("Incorrect board name '%s'", board.Name)
	}

	if board.LabelNames.Green != "Participate!" {
		t.Errorf("Expected Green label 'Participate!'. Got '%s'", board.LabelNames.Green)
	}
}

func TestGetBoardWithListsAndActions(t *testing.T) {
	board := testBoardWithListsAndActions(t)
	if board.Name != "Public Trello Boards" {
		t.Errorf("Incorrect board name '%s'", board.Name)
	}

	if len(board.Lists) != 4 {
		t.Errorf("Expected %d lists. Got %d", 4, len(board.Lists))
	}

	if len(board.Actions) != 43 {
		t.Errorf("Expected %d actions. Got %d", 4, len(board.Actions))
	}
}

func TestGetBoards(t *testing.T) {
	c := testClient()

	c.BaseURL = mockResponse("members", "api-example.json").URL
	member, err := c.GetMember("4ee7df1", Defaults())
	if err != nil {
		t.Fatal(err)
	}

	args := Defaults()
	args["lists"] = "all"

	c.BaseURL = mockResponse("boards", "member-boards-example.json").URL
	boards, err := member.GetBoards(args)
	if err != nil {
		t.Fatal(err)
	}

	if len(boards) != 2 {
		t.Errorf("Expected 2 boards. Got %d", len(boards))
	}

	if boards[0].Name != "Example Board" {
		t.Errorf("Name of first board incorrect. Got: '%s'", boards[0].Name)
	}

	if boards[1].Name != "Public Board" {
		t.Errorf("Name of second board incorrect. Got: '%s'", boards[1].Name)
	}

	if len(boards[1].Lists) != 1 {
		t.Error("Lists not sideloaded:", boards[0].Lists)
	}

	if boards[1].client != boards[1].Lists[0].client {
		t.Error("Client not passed to list")
	}
}

func TestGetMyBoards(t *testing.T) {
	c := testClient()

	c.BaseURL = mockResponse("boards", "member-boards-example.json").URL
	boards, err := c.GetMyBoards(Defaults())
	if err != nil {
		t.Fatal(err)
	}

	if len(boards) != 2 {
		t.Errorf("Expected 2 boards. Got %d", len(boards))
	}

	if boards[0].Name != "Example Board" {
		t.Errorf("Name of first board incorrect. Got: '%s'", boards[0].Name)
	}

	if boards[1].Name != "Public Board" {
		t.Errorf("Name of second board incorrect. Got: '%s'", boards[1].Name)
	}
}

func TestGetUnauthorizedBoard(t *testing.T) {
	c := testClient()
	c.BaseURL = mockErrorResponse(401).URL

	_, err := c.GetBoard("boardid", Defaults())
	if err == nil {
		t.Error("GetBoard() should have failed")
	}
}

func testBoard(t *testing.T) *Board {
	c := testClient()
	boardResponse := mockResponse("boards", "cI66RoQS.json")
	c.BaseURL = boardResponse.URL
	board, err := c.GetBoard("cIRoQS", Defaults())
	if err != nil {
		t.Fatal(err)
	}
	return board
}

func TestBoardUpdate(t *testing.T) {
	expected := map[string]map[string]string{
		"created": map[string]string{
			"id":          "5d2ccd3015468d3df508f10d",
			"name":        "test-board-for-update",
			"description": "Some description",
			"cardAging":   "regular",
		},
		"updated": map[string]string{
			"id":          "5d2ccd3015468d3df508f10d",
			"name":        "test-board-for-update plus",
			"description": "Some other description",
			"cardAging":   "pirate",
		},
	}

	board := Board{
		ID:   expected["created"]["id"],
		Name: expected["created"]["name"],
		Desc: expected["created"]["description"],
	}
	board.Prefs.CardAging = "regular"

	client := testClient()
	board.client = client
	boardResponse := mockResponse("boards", "5d2ccd3015468d3df508f10d", "create.json")
	client.BaseURL = boardResponse.URL

	err := client.CreateBoard(&board, Defaults())
	if err != nil {
		t.Error(err)
	}
	if board.ID != expected["created"]["id"] {
		t.Errorf("Expected board to pick up ID. Instead got '%s'.", board.ID)
	}
	if board.Name != expected["created"]["name"] {
		t.Errorf("Expected board name. Instead got '%s'.", board.Name)
	}
	if board.Desc != expected["created"]["description"] {
		t.Errorf("Expected board description. Instead got '%s'.", board.Desc)
	}
	if board.Prefs.CardAging != expected["created"]["cardAging"] {
		t.Errorf("Expected board's card aging. Instead got '%s'.", board.Prefs.CardAging)
	}

	board.Name = expected["updated"]["name"]
	board.Desc = expected["updated"]["description"]
	board.Prefs.CardAging = expected["updated"]["cardAging"]

	boardResponse = mockResponse("boards", "5d2ccd3015468d3df508f10d", "update.json")
	client.BaseURL = boardResponse.URL

	err = board.Update(Defaults())
	if err != nil {
		t.Fatal(err)
	}

	if board.ID != expected["updated"]["id"] {
		t.Errorf("Expected board to pick up ID. Instead got '%s'.", board.ID)
	}
	if board.Name != expected["updated"]["name"] {
		t.Errorf("Expected board name. Instead got '%s'.", board.Name)
	}
	if board.Desc != expected["updated"]["description"] {
		t.Errorf("Expected board description. Instead got '%s'.", board.Desc)
	}
	if board.Prefs.CardAging != expected["updated"]["cardAging"] {
		t.Errorf("Expected board's card aging. Instead got '%s'.", board.Prefs.CardAging)
	}

	return
}

func testBoardWithListsAndActions(t *testing.T) *Board {
	c := testClient()
	boardResponse := mockResponse("boards", "rq2mYJNn.json")
	c.BaseURL = boardResponse.URL
	board, err := c.GetBoard("rq2mYJNn", Defaults())
	if err != nil {
		t.Fatal(err)
	}
	return board
}

func TestBoardAddMember(t *testing.T) {
	board := Board{
		ID:   "5d2ccd3015468d3df508f10d",
		Name: "Test Board Create",
	}

	client := testClient()
	board.client = client

	boardResponse := mockResponse("boards/5d2ccd3015468d3df508f10d", "added_members.json")
	client.BaseURL = boardResponse.URL

	member := Member{Email: "test@test.com"}

	response, err := board.AddMember(&member, Arguments{"type": "fake"})
	if err != nil {
		t.Error(err)
	}

	if response.ID != "5d2ccd3015468d3df508f10d" {
		t.Errorf("Name of first board incorrect. Got: '%s'", response.ID)
	}

	if len(response.Members) != 2 {
		t.Errorf("Expected 2 members, got %d", len(response.Members))
	}

	if response.Members[1].Username != "user98198126" {
		t.Errorf("Username of invited member incorrect, got %s", response.Members[1].Username)
	}

	if response.Members[1].FullName != "user" {
		t.Errorf("Full name of invited member incorrect, got %s", response.Members[1].FullName)
	}

	if len(response.Memberships) != 2 {
		t.Errorf("Expected 2 memberships, got %d", len(response.Memberships))
	}

	if response.Memberships[1].Type != "normal" {
		t.Errorf("Type of membership incorrect, got %v", response.Memberships[1].Type)
	}

	if response.Memberships[1].Unconfirmed != true {
		t.Errorf("Status membership incorrect, got %v", response.Memberships[1].Unconfirmed)
	}
}
<commit_msg>Remove redundant map spec.<commit_after>// Copyright © 2016 Aaron Longwell
//
// Use of this source code is governed by an MIT license.
// Details in the LICENSE file.

package trello

import (
	"testing"
	"time"
)

func TestCreateBoard(t *testing.T) {
	c := testClient()
	c.BaseURL = mockResponse("boards", "AkFGHS12.json").URL

	board := Board{
		Name: "Test Board Create",
	}

	err := c.CreateBoard(&board, Defaults())
	if err != nil {
		t.Error(err)
	}

	if board.ID != "5c602cf77061a8169a69deb5" {
		t.Errorf("Expected board to pick up an ID. Instead got '%s'.", board.ID)
	}
}

func TestDeleteBoard(t *testing.T) {
	c := testClient()
	c.BaseURL = mockResponse("boards", "deleted.json").URL

	board := Board{
		ID:   "5c602cf77061a8169a69deb5",
		Name: "Test Board Create",
	}
	board.client = c

	err := board.Delete(Defaults())
	if err != nil {
		t.Error(err)
	}
}

func TestBoardCreatedAt(t *testing.T) {
	b := Board{ID: "4d5ea62fd76aa1136000000c"}
	ts := b.CreatedAt()
	if ts.IsZero() {
		t.Error("Time shouldn't be zero.")
	}
	if ts.Unix() != 1298048559 {
		t.Errorf("Incorrect CreatedAt() time: '%s'.", ts.Format(time.RFC3339))
	}
}

func TestGetBoard(t *testing.T) {
	board := testBoard(t)
	if board.Name != "Trello Public API" {
		t.Errorf("Incorrect board name '%s'", board.Name)
	}

	if board.LabelNames.Green != "Participate!" {
		t.Errorf("Expected Green label 'Participate!'. Got '%s'", board.LabelNames.Green)
	}
}

func TestGetBoardWithListsAndActions(t *testing.T) {
	board := testBoardWithListsAndActions(t)
	if board.Name != "Public Trello Boards" {
		t.Errorf("Incorrect board name '%s'", board.Name)
	}

	if len(board.Lists) != 4 {
		t.Errorf("Expected %d lists. Got %d", 4, len(board.Lists))
	}

	if len(board.Actions) != 43 {
		t.Errorf("Expected %d actions. Got %d", 4, len(board.Actions))
	}
}

func TestGetBoards(t *testing.T) {
	c := testClient()

	c.BaseURL = mockResponse("members", "api-example.json").URL
	member, err := c.GetMember("4ee7df1", Defaults())
	if err != nil {
		t.Fatal(err)
	}

	args := Defaults()
	args["lists"] = "all"

	c.BaseURL = mockResponse("boards", "member-boards-example.json").URL
	boards, err := member.GetBoards(args)
	if err != nil {
		t.Fatal(err)
	}

	if len(boards) != 2 {
		t.Errorf("Expected 2 boards. Got %d", len(boards))
	}

	if boards[0].Name != "Example Board" {
		t.Errorf("Name of first board incorrect. Got: '%s'", boards[0].Name)
	}

	if boards[1].Name != "Public Board" {
		t.Errorf("Name of second board incorrect. Got: '%s'", boards[1].Name)
	}

	if len(boards[1].Lists) != 1 {
		t.Error("Lists not sideloaded:", boards[0].Lists)
	}

	if boards[1].client != boards[1].Lists[0].client {
		t.Error("Client not passed to list")
	}
}

func TestGetMyBoards(t *testing.T) {
	c := testClient()

	c.BaseURL = mockResponse("boards", "member-boards-example.json").URL
	boards, err := c.GetMyBoards(Defaults())
	if err != nil {
		t.Fatal(err)
	}

	if len(boards) != 2 {
		t.Errorf("Expected 2 boards. Got %d", len(boards))
	}

	if boards[0].Name != "Example Board" {
		t.Errorf("Name of first board incorrect. Got: '%s'", boards[0].Name)
	}

	if boards[1].Name != "Public Board" {
		t.Errorf("Name of second board incorrect. Got: '%s'", boards[1].Name)
	}
}

func TestGetUnauthorizedBoard(t *testing.T) {
	c := testClient()
	c.BaseURL = mockErrorResponse(401).URL

	_, err := c.GetBoard("boardid", Defaults())
	if err == nil {
		t.Error("GetBoard() should have failed")
	}
}

func testBoard(t *testing.T) *Board {
	c := testClient()
	boardResponse := mockResponse("boards", "cI66RoQS.json")
	c.BaseURL = boardResponse.URL
	board, err := c.GetBoard("cIRoQS", Defaults())
	if err != nil {
		t.Fatal(err)
	}
	return board
}

func TestBoardUpdate(t *testing.T) {
	expected := map[string]map[string]string{
		"created": {
			"id":          "5d2ccd3015468d3df508f10d",
			"name":        "test-board-for-update",
			"description": "Some description",
			"cardAging":   "regular",
		},
		"updated": {
			"id":          "5d2ccd3015468d3df508f10d",
			"name":        "test-board-for-update plus",
			"description": "Some other description",
			"cardAging":   "pirate",
		},
	}

	board := Board{
		ID:   expected["created"]["id"],
		Name: expected["created"]["name"],
		Desc: expected["created"]["description"],
	}
	board.Prefs.CardAging = "regular"

	client := testClient()
	board.client = client
	boardResponse := mockResponse("boards", "5d2ccd3015468d3df508f10d", "create.json")
	client.BaseURL = boardResponse.URL

	err := client.CreateBoard(&board, Defaults())
	if err != nil {
		t.Error(err)
	}
	if board.ID != expected["created"]["id"] {
		t.Errorf("Expected board to pick up ID. Instead got '%s'.", board.ID)
	}
	if board.Name != expected["created"]["name"] {
		t.Errorf("Expected board name. Instead got '%s'.", board.Name)
	}
	if board.Desc != expected["created"]["description"] {
		t.Errorf("Expected board description. Instead got '%s'.", board.Desc)
	}
	if board.Prefs.CardAging != expected["created"]["cardAging"] {
		t.Errorf("Expected board's card aging. Instead got '%s'.", board.Prefs.CardAging)
	}

	board.Name = expected["updated"]["name"]
	board.Desc = expected["updated"]["description"]
	board.Prefs.CardAging = expected["updated"]["cardAging"]

	boardResponse = mockResponse("boards", "5d2ccd3015468d3df508f10d", "update.json")
	client.BaseURL = boardResponse.URL

	err = board.Update(Defaults())
	if err != nil {
		t.Fatal(err)
	}

	if board.ID != expected["updated"]["id"] {
		t.Errorf("Expected board to pick up ID. Instead got '%s'.", board.ID)
	}
	if board.Name != expected["updated"]["name"] {
		t.Errorf("Expected board name. Instead got '%s'.", board.Name)
	}
	if board.Desc != expected["updated"]["description"] {
		t.Errorf("Expected board description. Instead got '%s'.", board.Desc)
	}
	if board.Prefs.CardAging != expected["updated"]["cardAging"] {
		t.Errorf("Expected board's card aging. Instead got '%s'.", board.Prefs.CardAging)
	}

	return
}

func testBoardWithListsAndActions(t *testing.T) *Board {
	c := testClient()
	boardResponse := mockResponse("boards", "rq2mYJNn.json")
	c.BaseURL = boardResponse.URL
	board, err := c.GetBoard("rq2mYJNn", Defaults())
	if err != nil {
		t.Fatal(err)
	}
	return board
}

func TestBoardAddMember(t *testing.T) {
	board := Board{
		ID:   "5d2ccd3015468d3df508f10d",
		Name: "Test Board Create",
	}

	client := testClient()
	board.client = client

	boardResponse := mockResponse("boards/5d2ccd3015468d3df508f10d", "added_members.json")
	client.BaseURL = boardResponse.URL

	member := Member{Email: "test@test.com"}

	response, err := board.AddMember(&member, Arguments{"type": "fake"})
	if err != nil {
		t.Error(err)
	}

	if response.ID != "5d2ccd3015468d3df508f10d" {
		t.Errorf("Name of first board incorrect. Got: '%s'", response.ID)
	}

	if len(response.Members) != 2 {
		t.Errorf("Expected 2 members, got %d", len(response.Members))
	}

	if response.Members[1].Username != "user98198126" {
		t.Errorf("Username of invited member incorrect, got %s", response.Members[1].Username)
	}

	if response.Members[1].FullName != "user" {
		t.Errorf("Full name of invited member incorrect, got %s", response.Members[1].FullName)
	}

	if len(response.Memberships) != 2 {
		t.Errorf("Expected 2 memberships, got %d", len(response.Memberships))
	}

	if response.Memberships[1].Type != "normal" {
		t.Errorf("Type of membership incorrect, got %v", response.Memberships[1].Type)
	}

	if response.Memberships[1].Unconfirmed != true {
		t.Errorf("Status membership incorrect, got %v", response.Memberships[1].Unconfirmed)
	}
}
<|endoftext|>


<commit_before>package uzbl

import (
	"fmt"
	"strings"
)

type Keys []Key

func (keys Keys) Display() string {
	ss := make([]string, len(keys))
	for i, k := range keys {
		ss[i] = k.String()
	}
	return strings.Join(ss, " ")
}

func (keys Keys) String() string {
	ss := make([]string, len(keys))
	for i, k := range keys {
		ss[i] = k.String()
	}
	return strings.Join(ss, "")
}

const (
	ctrl = 1 << iota
	shift
	mod1
	mod2
	mod3
	mod4
	mod5
	mod6
)

var modNames = []struct {
	mod  int
	name string
}{
	{ctrl, "C"},
	{shift, "S"},
	{mod1, "1"},
	{mod2, "2"},
	{mod3, "3"},
	{mod4, "4"},
	{mod5, "5"},
	{mod6, "6"},
}

type Key struct {
	key string
	mod int
}

func (key Key) String() string {
	var mods string
	for _, mod := range modNames {
		if (key.mod & mod.mod) > 0 {
			mods += mod.name + "-"
		}
	}
	return mods + key.key
}

func parseMod(s string) int {
	mods := 0
	for _, mod := range strings.Split(s, "|") {
		switch mod {
		case "Shift":
			mods |= shift
		case "Ctrl":
			mods |= ctrl
		case "Mod1":
			mods |= mod1
		case "Mod2":
			mods |= mod2
		case "Mod3":
			mods |= mod3
		case "Mod4":
			mods |= mod4
		case "Mod5":
			mods |= mod5
		case "Mod6":
			mods |= mod6
		}
	}
	return mods
}

func parseBind(s string) *keyBind {
	bind := &keyBind{}
	var keys Keys
	for _, k := range strings.Split(s, " ") {
		// TODO handle invalid input
		key := k
		mod := 0
		if len(k) > 1 {
			parts := strings.Split(k, "-")
			key = parts[len(parts)-1]
			mods := parts[0 : len(parts)-1]

			for _, m := range mods {
				switch m {
				case "C":
					mod |= ctrl
				case "1":
					mod |= mod1
				case "2":
					mod |= mod2
				case "3":
					mod |= mod3
				case "4":
					mod |= mod4
				case "5":
					mod |= mod5
				case "6":
					mod |= mod6
				case "S":
					mod |= shift
				}
			}
		}

		if key == "<space>" {
			key = " "
		}
		keys = append(keys, Key{key: key, mod: mod})
	}

	if keys[len(keys)-1].key == "<*>" {
		bind.incremental = true
	}

	bind.bind = keys
	return bind
}

type keyBind struct {
	bind        Keys
	fn          func(ev *Event, input Keys) error
	incremental bool
	// TODO support the ! modifier?
}

func (b *keyBind) matches(input Keys) bool {
	if len(input) < len(b.bind) {
		return false
	}

	if len(input) > len(b.bind) && !b.incremental {
		return false
	}

	l := len(b.bind)
	if b.incremental {
		l -= 1
	}

	for i := 0; i < l; i++ {
		if b.bind[i].key != input[i].key || b.bind[i].mod != input[i].mod {
			return false
		}
	}

	return true
}

func NewInputManager(u *Uzbl) *InputManager {
	im := &InputManager{uzbl: u}
	u.EM.AddHandler("KEY_PRESS", im.EvKeyPress)
	u.EM.AddHandler("BIND", im.EvBind)
	u.EM.AddHandler("INSERT_MODE", im.EvInsertMode)
	u.EM.AddHandler("ESCAPE", im.EvEscape)
	u.EM.AddHandler("INSTANCE_START", im.EvInstanceStart)
	return im
}

const (
	commandMode = 0
	insertMode  = 1
)

type InputManager struct {
	// TODO support insert mode
	// TODO support : mode
	uzbl   *Uzbl
	binds  []*keyBind
	input  Keys
	prompt string
	mode   int
}

func (im *InputManager) Bind(s string, fn func(ev *Event, input Keys) error) {
	bind := parseBind(s)
	bind.fn = fn
	im.binds = append(im.binds, bind)
}

func (im *InputManager) EvKeyPress(ev *Event) error {
	parts := ev.ParseDetail(-1)
	mods, key := parseMod(parts[0]), parts[1]
	if len(key) == 1 {
		mods &^= shift
	}

	if key == "Escape" {
		im.uzbl.Send("event ESCAPE")
		return nil
	}

	if im.mode == insertMode {
		return nil
	}

	if key == "BackSpace" {
		if len(im.input) == 0 {
			return nil
		}
		im.input = im.input[0 : len(im.input)-1]
		im.setKeycmd()
	} else {
		// TODO way to not print spaces between characters, and not to use
		// <space>, so we can type urls etc

		if key == "space" {
			key = " "
		}

		if len(key) > 1 {
			key = "<" + key + ">"
		}
		im.input = append(im.input, Key{key: key, mod: mods})
		im.setKeycmd()
	}

	// FIXME incremental binds + Return

	bind, ok := im.findBind(im.input)
	if !ok {
		return nil
	}

	if key == "<Return>" && bind.incremental {
		im.input = nil
		im.setKeycmd()
		return nil
	}

	var err error
	if bind.incremental {
		err = bind.fn(ev, im.input[len(bind.bind)-1:])
	} else {
		err = bind.fn(ev, nil)
	}

	if !bind.incremental || key == "<Return>" {
		im.input = nil
		im.setKeycmd()
	}

	return err
}

func (im *InputManager) setKeycmd() {
	im.uzbl.Send(fmt.Sprintf("set keycmd_prompt = %s", im.prompt))
	im.uzbl.Send(fmt.Sprintf("set keycmd = %s", im.input.Display()))
}

func (im *InputManager) setModeIndicator() {
	name := ""
	switch im.mode {
	case commandMode:
		name = "Cmd"
	case insertMode:
		name = "Ins"
	default:
		name = "Error!"
	}
	im.uzbl.Send(fmt.Sprintf("set mode_indicator = %s", name))
}

func (im *InputManager) EvBind(ev *Event) error {
	args := ev.ParseDetail(3)
	im.Bind(args[0], CommandFn(args[1])) // TODO repeat
	return nil
}

func (im *InputManager) EvInsertMode(ev *Event) error {
	im.mode = insertMode
	im.uzbl.Send("set forward_keys = 1")
	im.setModeIndicator()
	return nil
}

func (im *InputManager) EvEscape(ev *Event) error {
	if im.mode == commandMode {
		im.input = nil
		im.setKeycmd()
		return nil
	}
	im.mode = commandMode
	im.uzbl.Send("set forward_keys = 0")
	im.setModeIndicator()
	return nil
}

func (im *InputManager) EvInstanceStart(ev *Event) error {
	im.setModeIndicator()
	return nil
}

func (im *InputManager) findBind(input Keys) (*keyBind, bool) {
	// TODO if we ever end up with enough binds to make this slow,
	// consider a tree-based implementation.
	for _, b := range im.binds {
		if b.matches(input) {
			return b, true
		}
	}
	return nil, false
}
<commit_msg>escape spaces before setting keycmd<commit_after>package uzbl

import (
	"fmt"
	"strings"
)

type Keys []Key

func (keys Keys) Display() string {
	ss := make([]string, len(keys))
	for i, k := range keys {
		ss[i] = k.String()
	}
	return strings.Join(ss, " ")
}

func (keys Keys) String() string {
	ss := make([]string, len(keys))
	for i, k := range keys {
		ss[i] = k.String()
	}
	return strings.Join(ss, "")
}

const (
	ctrl = 1 << iota
	shift
	mod1
	mod2
	mod3
	mod4
	mod5
	mod6
)

var modNames = []struct {
	mod  int
	name string
}{
	{ctrl, "C"},
	{shift, "S"},
	{mod1, "1"},
	{mod2, "2"},
	{mod3, "3"},
	{mod4, "4"},
	{mod5, "5"},
	{mod6, "6"},
}

type Key struct {
	key string
	mod int
}

func (key Key) String() string {
	var mods string
	for _, mod := range modNames {
		if (key.mod & mod.mod) > 0 {
			mods += mod.name + "-"
		}
	}
	return mods + key.key
}

func parseMod(s string) int {
	mods := 0
	for _, mod := range strings.Split(s, "|") {
		switch mod {
		case "Shift":
			mods |= shift
		case "Ctrl":
			mods |= ctrl
		case "Mod1":
			mods |= mod1
		case "Mod2":
			mods |= mod2
		case "Mod3":
			mods |= mod3
		case "Mod4":
			mods |= mod4
		case "Mod5":
			mods |= mod5
		case "Mod6":
			mods |= mod6
		}
	}
	return mods
}

func parseBind(s string) *keyBind {
	bind := &keyBind{}
	var keys Keys
	for _, k := range strings.Split(s, " ") {
		// TODO handle invalid input
		key := k
		mod := 0
		if len(k) > 1 {
			parts := strings.Split(k, "-")
			key = parts[len(parts)-1]
			mods := parts[0 : len(parts)-1]

			for _, m := range mods {
				switch m {
				case "C":
					mod |= ctrl
				case "1":
					mod |= mod1
				case "2":
					mod |= mod2
				case "3":
					mod |= mod3
				case "4":
					mod |= mod4
				case "5":
					mod |= mod5
				case "6":
					mod |= mod6
				case "S":
					mod |= shift
				}
			}
		}

		if key == "<space>" {
			key = " "
		}
		keys = append(keys, Key{key: key, mod: mod})
	}

	if keys[len(keys)-1].key == "<*>" {
		bind.incremental = true
	}

	bind.bind = keys
	return bind
}

type keyBind struct {
	bind        Keys
	fn          func(ev *Event, input Keys) error
	incremental bool
	// TODO support the ! modifier?
}

func (b *keyBind) matches(input Keys) bool {
	if len(input) < len(b.bind) {
		return false
	}

	if len(input) > len(b.bind) && !b.incremental {
		return false
	}

	l := len(b.bind)
	if b.incremental {
		l -= 1
	}

	for i := 0; i < l; i++ {
		if b.bind[i].key != input[i].key || b.bind[i].mod != input[i].mod {
			return false
		}
	}

	return true
}

func NewInputManager(u *Uzbl) *InputManager {
	im := &InputManager{uzbl: u}
	u.EM.AddHandler("KEY_PRESS", im.EvKeyPress)
	u.EM.AddHandler("BIND", im.EvBind)
	u.EM.AddHandler("INSERT_MODE", im.EvInsertMode)
	u.EM.AddHandler("ESCAPE", im.EvEscape)
	u.EM.AddHandler("INSTANCE_START", im.EvInstanceStart)
	return im
}

const (
	commandMode = 0
	insertMode  = 1
)

type InputManager struct {
	// TODO support insert mode
	// TODO support : mode
	uzbl   *Uzbl
	binds  []*keyBind
	input  Keys
	prompt string
	mode   int
}

func (im *InputManager) Bind(s string, fn func(ev *Event, input Keys) error) {
	bind := parseBind(s)
	bind.fn = fn
	im.binds = append(im.binds, bind)
}

func (im *InputManager) EvKeyPress(ev *Event) error {
	parts := ev.ParseDetail(-1)
	mods, key := parseMod(parts[0]), parts[1]
	if len(key) == 1 {
		mods &^= shift
	}

	if key == "Escape" {
		im.uzbl.Send("event ESCAPE")
		return nil
	}

	if im.mode == insertMode {
		return nil
	}

	if key == "BackSpace" {
		if len(im.input) == 0 {
			return nil
		}
		im.input = im.input[0 : len(im.input)-1]
		im.setKeycmd()
	} else {
		// TODO way to not print spaces between characters, and not to use
		// <space>, so we can type urls etc

		if key == "space" {
			key = " "
		}

		if len(key) > 1 {
			key = "<" + key + ">"
		}
		im.input = append(im.input, Key{key: key, mod: mods})
		im.setKeycmd()
	}

	// FIXME incremental binds + Return

	bind, ok := im.findBind(im.input)
	if !ok {
		return nil
	}

	if key == "<Return>" && bind.incremental {
		im.input = nil
		im.setKeycmd()
		return nil
	}

	var err error
	if bind.incremental {
		err = bind.fn(ev, im.input[len(bind.bind)-1:])
	} else {
		err = bind.fn(ev, nil)
	}

	if !bind.incremental || key == "<Return>" {
		im.input = nil
		im.setKeycmd()
	}

	return err
}

func (im *InputManager) setKeycmd() {
	im.uzbl.Send(fmt.Sprintf("set keycmd_prompt = %s", im.prompt))
	chain := im.input.Display()
	chain = strings.Replace(chain, " ", "\\ ", -1)
	im.uzbl.Send(fmt.Sprintf("set keycmd = %s", chain))
}

func (im *InputManager) setModeIndicator() {
	name := ""
	switch im.mode {
	case commandMode:
		name = "Cmd"
	case insertMode:
		name = "Ins"
	default:
		name = "Error!"
	}
	im.uzbl.Send(fmt.Sprintf("set mode_indicator = %s", name))
}

func (im *InputManager) EvBind(ev *Event) error {
	args := ev.ParseDetail(3)
	im.Bind(args[0], CommandFn(args[1])) // TODO repeat
	return nil
}

func (im *InputManager) EvInsertMode(ev *Event) error {
	im.mode = insertMode
	im.uzbl.Send("set forward_keys = 1")
	im.setModeIndicator()
	return nil
}

func (im *InputManager) EvEscape(ev *Event) error {
	if im.mode == commandMode {
		im.input = nil
		im.setKeycmd()
		return nil
	}
	im.mode = commandMode
	im.uzbl.Send("set forward_keys = 0")
	im.setModeIndicator()
	return nil
}

func (im *InputManager) EvInstanceStart(ev *Event) error {
	im.setModeIndicator()
	return nil
}

func (im *InputManager) findBind(input Keys) (*keyBind, bool) {
	// TODO if we ever end up with enough binds to make this slow,
	// consider a tree-based implementation.
	for _, b := range im.binds {
		if b.matches(input) {
			return b, true
		}
	}
	return nil, false
}
<|endoftext|>


<commit_before>package stage0

//
// Rocket is a reference implementation of the app container specification.
//
// Execution on Rocket is divided into a number of stages, and the `rkt`
// binary implements the first stage (stage 0)
//

import (
	"archive/tar"
	"bytes"
	"compress/bzip2"
	"compress/gzip"
	"crypto/sha256"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"syscall"

	"github.com/coreos/rocket/Godeps/_workspace/src/code.google.com/p/go-uuid/uuid"
	"github.com/coreos/rocket/app-container/aci"
	"github.com/coreos/rocket/app-container/schema"
	"github.com/coreos/rocket/app-container/schema/types"
	"github.com/coreos/rocket/cas"
	rktpath "github.com/coreos/rocket/path"
	ptar "github.com/coreos/rocket/pkg/tar"
	"github.com/coreos/rocket/version"

	"github.com/coreos/rocket/stage0/stage1_init"
	"github.com/coreos/rocket/stage0/stage1_rootfs"
)

const (
	initPath = "stage1/init"
)

type Config struct {
	Store         *cas.Store
	ContainersDir string // root directory for rocket containers
	Stage1Init    string // binary to be execed as stage1
	Stage1Rootfs  string // compressed bundle containing a rootfs for stage1
	Debug         bool
	Images        []string          // application images
	Volumes       map[string]string // map of volumes that rocket can provide to applications
}

func init() {
	log.SetOutput(ioutil.Discard)
}

// Setup sets up a filesystem for a container based on the given config.
// The directory containing the filesystem is returned, and any error encountered.
func Setup(cfg Config) (string, error) {
	if cfg.Debug {
		log.SetOutput(os.Stderr)
	}

	cuuid, err := types.NewUUID(uuid.New())
	if err != nil {
		return "", fmt.Errorf("error creating UID: %v", err)
	}

	// TODO(jonboulle): collision detection/mitigation
	// Create a directory for this container
	dir := filepath.Join(cfg.ContainersDir, cuuid.String())

	if err := os.MkdirAll(dir, 0700); err != nil {
		return "", fmt.Errorf("error creating directory: %v", err)
	}

	log.Printf("Unpacking stage1 rootfs")
	if cfg.Stage1Rootfs != "" {
		if err = unpackRootfs(cfg.Stage1Rootfs, rktpath.Stage1RootfsPath(dir)); err != nil {
			return "", fmt.Errorf("error unpacking rootfs: %v", err)
		}
	} else {
		if err = unpackBuiltinRootfs(rktpath.Stage1RootfsPath(dir)); err != nil {
			return "", fmt.Errorf("error unpacking rootfs: %v", err)
		}
	}

	log.Printf("Writing stage1 init")
	var in io.Reader
	if cfg.Stage1Init != "" {
		in, err = os.Open(cfg.Stage1Init)
		if err != nil {
			return "", fmt.Errorf("error loading stage1 init binary: %v", err)
		}
	} else {
		init_bin, err := stage1_init.Asset("s1init")
		if err != nil {
			return "", fmt.Errorf("error accessing stage1 init bindata: %v", err)
		}
		in = bytes.NewBuffer(init_bin)
	}
	fn := filepath.Join(dir, initPath)
	out, err := os.OpenFile(fn, os.O_CREATE|os.O_WRONLY, 0555)
	if err != nil {
		return "", fmt.Errorf("error opening stage1 init for writing: %v", err)
	}
	if _, err := io.Copy(out, in); err != nil {
		return "", fmt.Errorf("error writing stage1 init: %v", err)
	}
	if err := out.Close(); err != nil {
		return "", fmt.Errorf("error closing stage1 init: %v", err)
	}

	log.Printf("Wrote filesystem to %s\n", dir)

	cm := schema.ContainerRuntimeManifest{
		ACKind: "ContainerRuntimeManifest",
		UUID:   *cuuid,
		Apps:   make(schema.AppList, 0),
	}

	v, err := types.NewSemVer(version.Version)
	if err != nil {
		return "", fmt.Errorf("error creating version: %v", err)
	}
	cm.ACVersion = *v

	for _, img := range cfg.Images {
		h, err := types.NewHash(img)
		if err != nil {
			return "", fmt.Errorf("error: bad image hash %q: %v", img, err)
		}
		am, err := setupImage(cfg, img, *h, dir)
		if err != nil {
			return "", fmt.Errorf("error setting up image %s: %v", img, err)
		}
		if cm.Apps.Get(am.Name) != nil {
			return "", fmt.Errorf("error: multiple apps with name %s", am.Name)
		}
		a := schema.App{
			Name:        am.Name,
			ImageID:     *h,
			Isolators:   am.Isolators,
			Annotations: am.Annotations,
		}
		cm.Apps = append(cm.Apps, a)
	}

	var sVols []types.Volume
	for key, path := range cfg.Volumes {
		v := types.Volume{
			Kind:     "host",
			Source:   path,
			ReadOnly: true,
			Fulfills: []types.ACName{
				types.ACName(key),
			},
		}
		sVols = append(sVols, v)
	}
	// TODO(jonboulle): check that app mountpoint expectations are
	// satisfied here, rather than waiting for stage1
	cm.Volumes = sVols

	cdoc, err := json.Marshal(cm)
	if err != nil {
		return "", fmt.Errorf("error marshalling container manifest: %v", err)
	}

	log.Printf("Writing container manifest")
	fn = rktpath.ContainerManifestPath(dir)
	if err := ioutil.WriteFile(fn, cdoc, 0700); err != nil {
		return "", fmt.Errorf("error writing container manifest: %v", err)
	}
	return dir, nil
}

// Run actually runs the container by exec()ing the stage1 init inside
// the container filesystem.
func Run(dir string, debug bool) {
	log.Printf("Pivoting to filesystem %s", dir)
	if err := os.Chdir(dir); err != nil {
		log.Fatalf("failed changing to dir: %v", err)
	}

	log.Printf("Execing %s", initPath)
	args := []string{initPath}
	if debug {
		args = append(args, "debug")
	}
	if err := syscall.Exec(initPath, args, os.Environ()); err != nil {
		log.Fatalf("error execing init: %v", err)
	}
}

func untarRootfs(r io.Reader, dir string) error {
	tr := tar.NewReader(r)
	if err := os.MkdirAll(dir, 0776); err != nil {
		return fmt.Errorf("error creating stage1 rootfs directory: %v", err)
	}

	if err := ptar.ExtractTar(tr, dir); err != nil {
		return fmt.Errorf("error extracting rootfs: %v", err)
	}
	return nil
}

// unpackRootfs unpacks a stage1 rootfs (compressed file, pointed to by rfs)
// into dir, returning any error encountered
func unpackRootfs(rfs string, dir string) error {
	fh, err := os.Open(rfs)
	if err != nil {
		return fmt.Errorf("error opening stage1 rootfs: %v", err)
	}
	typ, err := aci.DetectFileType(fh)
	if err != nil {
		return fmt.Errorf("error detecting image type: %v", err)
	}
	if _, err := fh.Seek(0, 0); err != nil {
		return fmt.Errorf("error seeking image: %v", err)
	}
	var r io.Reader
	switch typ {
	case aci.TypeGzip:
		r, err = gzip.NewReader(fh)
		if err != nil {
			return fmt.Errorf("error reading gzip: %v", err)
		}
	case aci.TypeBzip2:
		r = bzip2.NewReader(fh)
	case aci.TypeXz:
		r = aci.XzReader(fh)
	case aci.TypeUnknown:
		return fmt.Errorf("error: unknown image filetype")
	default:
		// should never happen
		panic("no type returned from DetectFileType?")
	}

	if err := untarRootfs(r, dir); err != nil {
		return fmt.Errorf("error untarring rootfs")
	}

	return nil
}

// unpackBuiltinRootfs unpacks the included stage1 rootfs into dir
func unpackBuiltinRootfs(dir string) error {
	b, err := stage1_rootfs.Asset("s1rootfs.tar")
	if err != nil {
		return fmt.Errorf("error accessing rootfs asset: %v", err)
	}
	buf := bytes.NewBuffer(b)

	if err = untarRootfs(buf, dir); err != nil {
		return fmt.Errorf("error untarring rootfs")
	}

	return nil
}

// setupImage attempts to load the image by the given hash from the store,
// verifies that the image matches the given hash and extracts the image
// into a directory in the given dir.
// It returns the AppManifest that the image contains
func setupImage(cfg Config, img string, h types.Hash, dir string) (*schema.AppManifest, error) {
	log.Println("Loading image", img)

	rs, err := cfg.Store.ReadStream(img)
	if err != nil {
		return nil, err
	}

	ad := rktpath.AppImagePath(dir, h)
	err = os.MkdirAll(ad, 0776)
	if err != nil {
		return nil, fmt.Errorf("error creating image directory: %v", err)
	}

	hash := sha256.New()
	r := io.TeeReader(rs, hash)

	if err := ptar.ExtractTar(tar.NewReader(r), ad); err != nil {
		return nil, fmt.Errorf("error extracting ACI: %v", err)
	}

	if id := fmt.Sprintf("%x", hash.Sum(nil)); id != h.Val {
		if err := os.RemoveAll(ad); err != nil {
			fmt.Fprintf(os.Stderr, "error cleaning up directory: %v\n", err)
		}
		return nil, fmt.Errorf("image hash does not match expected (%v != %v)", id, h.Val)
	}

	err = os.MkdirAll(filepath.Join(ad, "rootfs/tmp"), 0777)
	if err != nil {
		return nil, fmt.Errorf("error creating tmp directory: %v", err)
	}

	mpath := rktpath.AppManifestPath(dir, h)
	f, err := os.Open(mpath)
	if err != nil {
		return nil, fmt.Errorf("error opening app manifest: %v", err)
	}
	b, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, fmt.Errorf("error reading app manifest: %v", err)
	}
	var am schema.AppManifest
	if err := json.Unmarshal(b, &am); err != nil {
		return nil, fmt.Errorf("error unmarshaling app manifest: %v", err)
	}
	return &am, nil
}
<commit_msg>stage0: ensure entire file is copied into hash<commit_after>package stage0

//
// Rocket is a reference implementation of the app container specification.
//
// Execution on Rocket is divided into a number of stages, and the `rkt`
// binary implements the first stage (stage 0)
//

import (
	"archive/tar"
	"bytes"
	"compress/bzip2"
	"compress/gzip"
	"crypto/sha256"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"syscall"

	"github.com/coreos/rocket/Godeps/_workspace/src/code.google.com/p/go-uuid/uuid"
	"github.com/coreos/rocket/app-container/aci"
	"github.com/coreos/rocket/app-container/schema"
	"github.com/coreos/rocket/app-container/schema/types"
	"github.com/coreos/rocket/cas"
	rktpath "github.com/coreos/rocket/path"
	ptar "github.com/coreos/rocket/pkg/tar"
	"github.com/coreos/rocket/version"

	"github.com/coreos/rocket/stage0/stage1_init"
	"github.com/coreos/rocket/stage0/stage1_rootfs"
)

const (
	initPath = "stage1/init"
)

type Config struct {
	Store         *cas.Store
	ContainersDir string // root directory for rocket containers
	Stage1Init    string // binary to be execed as stage1
	Stage1Rootfs  string // compressed bundle containing a rootfs for stage1
	Debug         bool
	Images        []string          // application images
	Volumes       map[string]string // map of volumes that rocket can provide to applications
}

func init() {
	log.SetOutput(ioutil.Discard)
}

// Setup sets up a filesystem for a container based on the given config.
// The directory containing the filesystem is returned, and any error encountered.
func Setup(cfg Config) (string, error) {
	if cfg.Debug {
		log.SetOutput(os.Stderr)
	}

	cuuid, err := types.NewUUID(uuid.New())
	if err != nil {
		return "", fmt.Errorf("error creating UID: %v", err)
	}

	// TODO(jonboulle): collision detection/mitigation
	// Create a directory for this container
	dir := filepath.Join(cfg.ContainersDir, cuuid.String())

	if err := os.MkdirAll(dir, 0700); err != nil {
		return "", fmt.Errorf("error creating directory: %v", err)
	}

	log.Printf("Unpacking stage1 rootfs")
	if cfg.Stage1Rootfs != "" {
		if err = unpackRootfs(cfg.Stage1Rootfs, rktpath.Stage1RootfsPath(dir)); err != nil {
			return "", fmt.Errorf("error unpacking rootfs: %v", err)
		}
	} else {
		if err = unpackBuiltinRootfs(rktpath.Stage1RootfsPath(dir)); err != nil {
			return "", fmt.Errorf("error unpacking rootfs: %v", err)
		}
	}

	log.Printf("Writing stage1 init")
	var in io.Reader
	if cfg.Stage1Init != "" {
		in, err = os.Open(cfg.Stage1Init)
		if err != nil {
			return "", fmt.Errorf("error loading stage1 init binary: %v", err)
		}
	} else {
		init_bin, err := stage1_init.Asset("s1init")
		if err != nil {
			return "", fmt.Errorf("error accessing stage1 init bindata: %v", err)
		}
		in = bytes.NewBuffer(init_bin)
	}
	fn := filepath.Join(dir, initPath)
	out, err := os.OpenFile(fn, os.O_CREATE|os.O_WRONLY, 0555)
	if err != nil {
		return "", fmt.Errorf("error opening stage1 init for writing: %v", err)
	}
	if _, err := io.Copy(out, in); err != nil {
		return "", fmt.Errorf("error writing stage1 init: %v", err)
	}
	if err := out.Close(); err != nil {
		return "", fmt.Errorf("error closing stage1 init: %v", err)
	}

	log.Printf("Wrote filesystem to %s\n", dir)

	cm := schema.ContainerRuntimeManifest{
		ACKind: "ContainerRuntimeManifest",
		UUID:   *cuuid,
		Apps:   make(schema.AppList, 0),
	}

	v, err := types.NewSemVer(version.Version)
	if err != nil {
		return "", fmt.Errorf("error creating version: %v", err)
	}
	cm.ACVersion = *v

	for _, img := range cfg.Images {
		h, err := types.NewHash(img)
		if err != nil {
			return "", fmt.Errorf("error: bad image hash %q: %v", img, err)
		}
		am, err := setupImage(cfg, img, *h, dir)
		if err != nil {
			return "", fmt.Errorf("error setting up image %s: %v", img, err)
		}
		if cm.Apps.Get(am.Name) != nil {
			return "", fmt.Errorf("error: multiple apps with name %s", am.Name)
		}
		a := schema.App{
			Name:        am.Name,
			ImageID:     *h,
			Isolators:   am.Isolators,
			Annotations: am.Annotations,
		}
		cm.Apps = append(cm.Apps, a)
	}

	var sVols []types.Volume
	for key, path := range cfg.Volumes {
		v := types.Volume{
			Kind:     "host",
			Source:   path,
			ReadOnly: true,
			Fulfills: []types.ACName{
				types.ACName(key),
			},
		}
		sVols = append(sVols, v)
	}
	// TODO(jonboulle): check that app mountpoint expectations are
	// satisfied here, rather than waiting for stage1
	cm.Volumes = sVols

	cdoc, err := json.Marshal(cm)
	if err != nil {
		return "", fmt.Errorf("error marshalling container manifest: %v", err)
	}

	log.Printf("Writing container manifest")
	fn = rktpath.ContainerManifestPath(dir)
	if err := ioutil.WriteFile(fn, cdoc, 0700); err != nil {
		return "", fmt.Errorf("error writing container manifest: %v", err)
	}
	return dir, nil
}

// Run actually runs the container by exec()ing the stage1 init inside
// the container filesystem.
func Run(dir string, debug bool) {
	log.Printf("Pivoting to filesystem %s", dir)
	if err := os.Chdir(dir); err != nil {
		log.Fatalf("failed changing to dir: %v", err)
	}

	log.Printf("Execing %s", initPath)
	args := []string{initPath}
	if debug {
		args = append(args, "debug")
	}
	if err := syscall.Exec(initPath, args, os.Environ()); err != nil {
		log.Fatalf("error execing init: %v", err)
	}
}

func untarRootfs(r io.Reader, dir string) error {
	tr := tar.NewReader(r)
	if err := os.MkdirAll(dir, 0776); err != nil {
		return fmt.Errorf("error creating stage1 rootfs directory: %v", err)
	}

	if err := ptar.ExtractTar(tr, dir); err != nil {
		return fmt.Errorf("error extracting rootfs: %v", err)
	}
	return nil
}

// unpackRootfs unpacks a stage1 rootfs (compressed file, pointed to by rfs)
// into dir, returning any error encountered
func unpackRootfs(rfs string, dir string) error {
	fh, err := os.Open(rfs)
	if err != nil {
		return fmt.Errorf("error opening stage1 rootfs: %v", err)
	}
	typ, err := aci.DetectFileType(fh)
	if err != nil {
		return fmt.Errorf("error detecting image type: %v", err)
	}
	if _, err := fh.Seek(0, 0); err != nil {
		return fmt.Errorf("error seeking image: %v", err)
	}
	var r io.Reader
	switch typ {
	case aci.TypeGzip:
		r, err = gzip.NewReader(fh)
		if err != nil {
			return fmt.Errorf("error reading gzip: %v", err)
		}
	case aci.TypeBzip2:
		r = bzip2.NewReader(fh)
	case aci.TypeXz:
		r = aci.XzReader(fh)
	case aci.TypeUnknown:
		return fmt.Errorf("error: unknown image filetype")
	default:
		// should never happen
		panic("no type returned from DetectFileType?")
	}

	if err := untarRootfs(r, dir); err != nil {
		return fmt.Errorf("error untarring rootfs")
	}

	return nil
}

// unpackBuiltinRootfs unpacks the included stage1 rootfs into dir
func unpackBuiltinRootfs(dir string) error {
	b, err := stage1_rootfs.Asset("s1rootfs.tar")
	if err != nil {
		return fmt.Errorf("error accessing rootfs asset: %v", err)
	}
	buf := bytes.NewBuffer(b)

	if err = untarRootfs(buf, dir); err != nil {
		return fmt.Errorf("error untarring rootfs")
	}

	return nil
}

// setupImage attempts to load the image by the given hash from the store,
// verifies that the image matches the given hash and extracts the image
// into a directory in the given dir.
// It returns the AppManifest that the image contains
func setupImage(cfg Config, img string, h types.Hash, dir string) (*schema.AppManifest, error) {
	log.Println("Loading image", img)

	rs, err := cfg.Store.ReadStream(img)
	if err != nil {
		return nil, err
	}

	ad := rktpath.AppImagePath(dir, h)
	err = os.MkdirAll(ad, 0776)
	if err != nil {
		return nil, fmt.Errorf("error creating image directory: %v", err)
	}

	hash := sha256.New()
	r := io.TeeReader(rs, hash)

	if err := ptar.ExtractTar(tar.NewReader(r), ad); err != nil {
		return nil, fmt.Errorf("error extracting ACI: %v", err)
	}

	// Tar does not necessarily read the complete file, so ensure we read the entirety into the hash
	if _, err := io.Copy(ioutil.Discard, r); err != nil {
		return nil, fmt.Errorf("error reading ACI: %v", err)
	}

	if id := fmt.Sprintf("%x", hash.Sum(nil)); id != h.Val {
		if err := os.RemoveAll(ad); err != nil {
			fmt.Fprintf(os.Stderr, "error cleaning up directory: %v\n", err)
		}
		return nil, fmt.Errorf("image hash does not match expected (%v != %v)", id, h.Val)
	}

	err = os.MkdirAll(filepath.Join(ad, "rootfs/tmp"), 0777)
	if err != nil {
		return nil, fmt.Errorf("error creating tmp directory: %v", err)
	}

	mpath := rktpath.AppManifestPath(dir, h)
	f, err := os.Open(mpath)
	if err != nil {
		return nil, fmt.Errorf("error opening app manifest: %v", err)
	}
	b, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, fmt.Errorf("error reading app manifest: %v", err)
	}
	var am schema.AppManifest
	if err := json.Unmarshal(b, &am); err != nil {
		return nil, fmt.Errorf("error unmarshaling app manifest: %v", err)
	}
	return &am, nil
}
<|endoftext|>


<commit_before>package bagman

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"strings"
)

type PartnerConfig struct {
	AwsAccessKeyId         string
	AwsSecretAccessKey     string
	ReceivingBucket        string
	RestorationBucket      string
	DownloadDir            string
	warnings               []string
}

func LoadPartnerConfig(configFile string) (*PartnerConfig, error) {
	file, err := os.Open(configFile)
	if err != nil {
		return nil, fmt.Errorf("Cannot open config file: %v", err)
	}
	defer file.Close()
	return parsePartnerConfig(file)
}

func parsePartnerConfig(file *os.File) (*PartnerConfig, error) {
	partnerConfig := &PartnerConfig{
		warnings: make([]string, 0),
	}
	bufReader := bufio.NewReader(file)
	lineNum := 0
	for {
		lineNum++
		line, err := bufReader.ReadString('\n')
		if err == io.EOF {
			break
		} else if err != nil {
			return nil, err
		}
		cleanLine := strings.TrimSpace(line)
		if strings.HasPrefix(cleanLine, "#") {
			continue
		}
		parts := strings.SplitN(cleanLine, "=", 2)
		if len(parts) != 2 {
			return nil, fmt.Errorf("Line %d is not valid. It should contain " +
				"a #comment or name=value setting.\n" +
				"Actual line: %s", lineNum, cleanLine)
		} else {
			partnerConfig.addSetting(parts[0], parts[1])
		}
	}
	partnerConfig.ExpandFilePaths()
	return partnerConfig, nil
}

func (partnerConfig *PartnerConfig) addSetting(name, value string) {
	cleanName := CleanString(name)
	cleanValue := CleanString(value)
	switch strings.ToLower(cleanName) {
	case "awsaccesskeyid": partnerConfig.AwsAccessKeyId = cleanValue
	case "awssecretaccesskey": partnerConfig.AwsSecretAccessKey = cleanValue
	case "receivingbucket": partnerConfig.ReceivingBucket = cleanValue
	case "restorationbucket": partnerConfig.RestorationBucket = cleanValue
	case "downloaddir": partnerConfig.DownloadDir = cleanValue
	default: partnerConfig.addWarning(fmt.Sprintf("Invalid setting: %s = %s", cleanName, cleanValue))
	}
}

func (partnerConfig *PartnerConfig) addWarning(message string) {
	partnerConfig.warnings = append(partnerConfig.warnings, message)
}

func (partnerConfig *PartnerConfig) Warnings() ([]string) {
	warnings := make([]string, len(partnerConfig.warnings))
	copy(warnings, partnerConfig.warnings)
	if partnerConfig.AwsAccessKeyId == "" {
		warnings = append(warnings,
			"AwsAccessKeyId is missing. This setting is required only for copying files " +
				"to and from S3. You may set this in the environment instead of in the config file " +
				"if you prefer.")
	}
	if partnerConfig.AwsSecretAccessKey == "" {
		warnings = append(warnings,
			"AwsSecretAccessKey is missing. This setting is required only for copying files " +
				"to and from S3. You may set this in the environment instead of in the config file " +
				"if you prefer.")
	}
	if partnerConfig.ReceivingBucket == "" {
		warnings = append(warnings,
			"ReceivingBucket is missing. This setting is required for uploading files to S3.")
	}
	if partnerConfig.RestorationBucket == "" {
		warnings = append(warnings,
			"RestorationBucket is missing. This setting is required for downloading restored files from S3.")
	}
	if partnerConfig.DownloadDir == "" {
		warnings = append(warnings,
			"DownloadDir is missing. This setting is required for downloading restored files from S3.")
	}
	return warnings
}

// Fill in AWS values if their missing from config file
// but present in the environment.
func (partnerConfig *PartnerConfig) LoadAwsFromEnv() {
	if partnerConfig.AwsAccessKeyId == "" && os.Getenv("AWS_ACCESS_KEY_ID") != "" {
		partnerConfig.AwsAccessKeyId = os.Getenv("AWS_ACCESS_KEY_ID")
	}
	if partnerConfig.AwsSecretAccessKey == "" && os.Getenv("AWS_SECRET_ACCESS_KEY") != "" {
		partnerConfig.AwsSecretAccessKey = os.Getenv("AWS_SECRET_ACCESS_KEY")
	}
}

func (partnerConfig *PartnerConfig) Validate() (error) {
	partnerConfig.ExpandFilePaths()
	if partnerConfig.AwsAccessKeyId == "" || partnerConfig.AwsSecretAccessKey == "" {
		partnerConfig.LoadAwsFromEnv()
	}
	if partnerConfig.AwsAccessKeyId == "" {
		return fmt.Errorf("AWS_ACCESS_KEY_ID is missing. This should be set in " +
			"the config file as AwsAccessKeyId or in the environment as AWS_ACCESS_KEY_ID.")
	}
	if partnerConfig.AwsSecretAccessKey == "" {
		return fmt.Errorf("AWS_SECRET_ACCESS_KEY is missing. This should be set in " +
			"the config file as AwsSecretAccessKey or in the environment as AWS_SECRET_ACCESS_KEY.")
	}
	if partnerConfig.ReceivingBucket == "" {
		return fmt.Errorf("Config file setting ReceivingBucket is missing.")
	}
	if partnerConfig.RestorationBucket == "" {
		return fmt.Errorf("Config file setting ReceivingBucket is missing.")
	}
	if partnerConfig.DownloadDir == "" {
		return fmt.Errorf("Config file setting DownloadDir is missing.")
	} else {
		err := os.MkdirAll(partnerConfig.DownloadDir, 0755)
		if err != nil {
			return fmt.Errorf("Cannot created DownloadDir '%s': %v", partnerConfig.DownloadDir, err)
		}
	}
	return nil
}

func (partnerConfig *PartnerConfig) ExpandFilePaths() {
	expanded, err := ExpandTilde(partnerConfig.DownloadDir)
	if err == nil {
		partnerConfig.DownloadDir = expanded
	}
}
<commit_msg>Allow blank lines in partner config file<commit_after>package bagman

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"strings"
)

type PartnerConfig struct {
	AwsAccessKeyId         string
	AwsSecretAccessKey     string
	ReceivingBucket        string
	RestorationBucket      string
	DownloadDir            string
	warnings               []string
}

func LoadPartnerConfig(configFile string) (*PartnerConfig, error) {
	file, err := os.Open(configFile)
	if err != nil {
		return nil, fmt.Errorf("Cannot open config file: %v", err)
	}
	defer file.Close()
	return parsePartnerConfig(file)
}

func parsePartnerConfig(file *os.File) (*PartnerConfig, error) {
	partnerConfig := &PartnerConfig{
		warnings: make([]string, 0),
	}
	bufReader := bufio.NewReader(file)
	lineNum := 0
	for {
		lineNum++
		line, err := bufReader.ReadString('\n')
		if err == io.EOF {
			break
		} else if err != nil {
			return nil, err
		}
		cleanLine := strings.TrimSpace(line)
		if cleanLine == "" || strings.HasPrefix(cleanLine, "#") {
			continue
		}
		parts := strings.SplitN(cleanLine, "=", 2)
		if len(parts) != 2 {
			return nil, fmt.Errorf("Line %d is not valid. It should contain " +
				"a #comment or name=value setting.\n" +
				"Actual line: %s", lineNum, cleanLine)
		} else {
			partnerConfig.addSetting(parts[0], parts[1])
		}
	}
	partnerConfig.ExpandFilePaths()
	return partnerConfig, nil
}

func (partnerConfig *PartnerConfig) addSetting(name, value string) {
	cleanName := CleanString(name)
	cleanValue := CleanString(value)
	switch strings.ToLower(cleanName) {
	case "awsaccesskeyid": partnerConfig.AwsAccessKeyId = cleanValue
	case "awssecretaccesskey": partnerConfig.AwsSecretAccessKey = cleanValue
	case "receivingbucket": partnerConfig.ReceivingBucket = cleanValue
	case "restorationbucket": partnerConfig.RestorationBucket = cleanValue
	case "downloaddir": partnerConfig.DownloadDir = cleanValue
	default: partnerConfig.addWarning(fmt.Sprintf("Invalid setting: %s = %s", cleanName, cleanValue))
	}
}

func (partnerConfig *PartnerConfig) addWarning(message string) {
	partnerConfig.warnings = append(partnerConfig.warnings, message)
}

func (partnerConfig *PartnerConfig) Warnings() ([]string) {
	warnings := make([]string, len(partnerConfig.warnings))
	copy(warnings, partnerConfig.warnings)
	if partnerConfig.AwsAccessKeyId == "" {
		warnings = append(warnings,
			"AwsAccessKeyId is missing. This setting is required only for copying files " +
				"to and from S3. You may set this in the environment instead of in the config file " +
				"if you prefer.")
	}
	if partnerConfig.AwsSecretAccessKey == "" {
		warnings = append(warnings,
			"AwsSecretAccessKey is missing. This setting is required only for copying files " +
				"to and from S3. You may set this in the environment instead of in the config file " +
				"if you prefer.")
	}
	if partnerConfig.ReceivingBucket == "" {
		warnings = append(warnings,
			"ReceivingBucket is missing. This setting is required for uploading files to S3.")
	}
	if partnerConfig.RestorationBucket == "" {
		warnings = append(warnings,
			"RestorationBucket is missing. This setting is required for downloading restored files from S3.")
	}
	if partnerConfig.DownloadDir == "" {
		warnings = append(warnings,
			"DownloadDir is missing. This setting is required for downloading restored files from S3.")
	}
	return warnings
}

// Fill in AWS values if their missing from config file
// but present in the environment.
func (partnerConfig *PartnerConfig) LoadAwsFromEnv() {
	if partnerConfig.AwsAccessKeyId == "" && os.Getenv("AWS_ACCESS_KEY_ID") != "" {
		partnerConfig.AwsAccessKeyId = os.Getenv("AWS_ACCESS_KEY_ID")
	}
	if partnerConfig.AwsSecretAccessKey == "" && os.Getenv("AWS_SECRET_ACCESS_KEY") != "" {
		partnerConfig.AwsSecretAccessKey = os.Getenv("AWS_SECRET_ACCESS_KEY")
	}
}

func (partnerConfig *PartnerConfig) Validate() (error) {
	partnerConfig.ExpandFilePaths()
	if partnerConfig.AwsAccessKeyId == "" || partnerConfig.AwsSecretAccessKey == "" {
		partnerConfig.LoadAwsFromEnv()
	}
	if partnerConfig.AwsAccessKeyId == "" {
		return fmt.Errorf("AWS_ACCESS_KEY_ID is missing. This should be set in " +
			"the config file as AwsAccessKeyId or in the environment as AWS_ACCESS_KEY_ID.")
	}
	if partnerConfig.AwsSecretAccessKey == "" {
		return fmt.Errorf("AWS_SECRET_ACCESS_KEY is missing. This should be set in " +
			"the config file as AwsSecretAccessKey or in the environment as AWS_SECRET_ACCESS_KEY.")
	}
	if partnerConfig.ReceivingBucket == "" {
		return fmt.Errorf("Config file setting ReceivingBucket is missing.")
	}
	if partnerConfig.RestorationBucket == "" {
		return fmt.Errorf("Config file setting ReceivingBucket is missing.")
	}
	if partnerConfig.DownloadDir == "" {
		return fmt.Errorf("Config file setting DownloadDir is missing.")
	} else {
		err := os.MkdirAll(partnerConfig.DownloadDir, 0755)
		if err != nil {
			return fmt.Errorf("Cannot created DownloadDir '%s': %v", partnerConfig.DownloadDir, err)
		}
	}
	return nil
}

func (partnerConfig *PartnerConfig) ExpandFilePaths() {
	expanded, err := ExpandTilde(partnerConfig.DownloadDir)
	if err == nil {
		partnerConfig.DownloadDir = expanded
	}
}
<|endoftext|>


<commit_before>package govaluate

import (
  "testing"
)

/*
  The most common use case, a single variable, modified slightly, compared to a constant.
  This is the "expected" use case of govaluate.
*/
func BenchmarkSimpleParse(bench *testing.B) {

  for i := 0; i < bench.N; i++ {
    NewEvaluableExpression("(requests_made * requests_succeeded / 100) >= 90")
  }
}

/*
  Benchmarks all syntax possibilities in one expression.
*/
func BenchmarkFullParse(bench *testing.B) {

  var expression string

  // represents all the major syntax possibilities.
  expression = "2 > 1 &&" +
               "'something != nothing || " +
               "'2014-01-20' < 'Wed Jul  8 23:07:35 MDT 2015' &&" +
               "[escapedVariable name with spaces] <= unescaped\\-variableName &&" +
               "modifierTest + 1000 / 2 > (80 * 100 % 2)"

  for i := 0; i < bench.N; i++ {
    NewEvaluableExpression(expression)
  }
}

/*
  Benchmarks evaluation times of literals (no variables, no modifiers)
*/
func BenchmarkEvaluationNumericLiteral(bench *testing.B) {

  expression, _ := NewEvaluableExpression("2 > 1")

  for i := 0; i < bench.N; i++ {
    expression.Evaluate(nil)
  }
}

/*
  Benchmarks evaluation times of literals with modifiers
*/
func BenchmarkEvaluationLiteralModifiers(bench *testing.B) {

  expression, _ := NewEvaluableExpression("2 + 2 == 4")

  for i := 0; i < bench.N; i++ {
    expression.Evaluate(nil)
  }
}

/*
  Benchmarks evaluation times of parameters + literals with modifiers
*/
func BenchmarkEvaluationParametersModifiers(bench *testing.B) {

  expression, _ := NewEvaluableExpression("(requests_made * requests_succeeded / 100) >= 90")
  parameters := map[string]interface{} {
    "requests_made": 99,
    "requests_succeeded": 90,
  }

  for i := 0; i < bench.N; i++ {
      expression.Evaluate(parameters)
  }
}
<commit_msg>Added benchmarks for complex expression evaluation<commit_after>package govaluate

import (
  "testing"
)

/*
  The most common use case, a single variable, modified slightly, compared to a constant.
  This is the "expected" use case of govaluate.
*/
func BenchmarkSimpleParse(bench *testing.B) {

  for i := 0; i < bench.N; i++ {
    NewEvaluableExpression("(requests_made * requests_succeeded / 100) >= 90")
  }
}

/*
  Benchmarks all syntax possibilities in one expression.
*/
func BenchmarkFullParse(bench *testing.B) {

  var expression string

  // represents all the major syntax possibilities.
  expression = "2 > 1 &&" +
               "'something != nothing || " +
               "'2014-01-20' < 'Wed Jul  8 23:07:35 MDT 2015' &&" +
               "[escapedVariable name with spaces] <= unescaped\\-variableName &&" +
               "modifierTest + 1000 / 2 > (80 * 100 % 2)"

  for i := 0; i < bench.N; i++ {
    NewEvaluableExpression(expression)
  }
}

/*
  Benchmarks evaluation times of literals (no variables, no modifiers)
*/
func BenchmarkEvaluationNumericLiteral(bench *testing.B) {

  expression, _ := NewEvaluableExpression("2 > 1")

  for i := 0; i < bench.N; i++ {
    expression.Evaluate(nil)
  }
}

/*
  Benchmarks evaluation times of literals with modifiers
*/
func BenchmarkEvaluationLiteralModifiers(bench *testing.B) {

  expression, _ := NewEvaluableExpression("2 + 2 == 4")

  for i := 0; i < bench.N; i++ {
    expression.Evaluate(nil)
  }
}

/*
  Benchmarks evaluation times of parameters
*/
func BenchmarkEvaluationParameters(bench *testing.B) {

  expression, _ := NewEvaluableExpression("requests_made > requests_succeeded")
  parameters := map[string]interface{} {
    "requests_made": 99.0,
    "requests_succeeded": 90.0,
  }

  for i := 0; i < bench.N; i++ {
      expression.Evaluate(parameters)
  }
}

/*
  Benchmarks evaluation times of parameters + literals with modifiers
*/
func BenchmarkEvaluationParametersModifiers(bench *testing.B) {

  expression, _ := NewEvaluableExpression("(requests_made * requests_succeeded / 100) >= 90")
  parameters := map[string]interface{} {
    "requests_made": 99.0,
    "requests_succeeded": 90.0,
  }

  for i := 0; i < bench.N; i++ {
      expression.Evaluate(parameters)
  }
}

/*
  Benchmarks the ludicrously-unlikely worst-case expression,
  one which uses all features.
  This is largely a canary benchmark to make sure that any syntax additions don't
  unnecessarily bloat the evaluation time.
*/
func BenchmarkComplexExpression(bench *testing.B) {

  var expressionString string

  expressionString = "2 > 1 &&" +
               "'something' != 'nothing' || " +
               "'2014-01-20' < 'Wed Jul  8 23:07:35 MDT 2015' && " +
               "[escapedVariable name with spaces] <= unescaped\\-variableName &&" +
               "modifierTest + 1000 / 2 > (80 * 100 % 2)"

  expression, _ := NewEvaluableExpression(expressionString)
  parameters := map[string]interface{} {
    "escapedVariable name with spaces": 99.0,
    "unescaped\\-variableName": 90.0,
    "modifierTest": 5.0,
  }

  for i := 0; i < bench.N; i++ {
     expression.Evaluate(parameters)
  }
}
<|endoftext|>


<commit_before>package server

import (
	"errors"
	"fmt"
	"os"
	"strings"
	"time"

	log "github.com/cihub/seelog"
	"github.com/golang/protobuf/proto"
	"github.com/streadway/amqp"

	"github.com/vinceprignano/bunny/rabbit"
)

type AMQPServer struct {
	// this is the routing key prefix for all endpoints
	ServiceName        string
	ServiceDescription string
	endpointRegistry   *EndpointRegistry
	connection         *rabbit.RabbitConnection
}

func NewAMQPServer() Server {
	return &AMQPServer{
		endpointRegistry: NewEndpointRegistry(),
		connection:       rabbit.NewRabbitConnection(),
	}
}

func (s *AMQPServer) Name() string {
	if s == nil {
		return ""
	}
	return s.ServiceName
}

func (s *AMQPServer) Description() string {
	if s == nil {
		return ""
	}
	return s.ServiceDescription
}

func (s *AMQPServer) Initialise(c *Config) {
	s.ServiceName = c.Name
	s.ServiceDescription = c.Description
}

func (s *AMQPServer) RegisterEndpoint(endpoint Endpoint) {
	s.endpointRegistry.Register(endpoint)
}

func (s *AMQPServer) DeregisterEndpoint(endpointName string) {
	s.endpointRegistry.Deregister(endpointName)
}

// Run the server, connecting to our transport and serving requests
func (s *AMQPServer) Run() {

	// Connect to AMQP
	select {
	case <-s.connection.Init():
		log.Info("[Server] Connected to RabbitMQ")
	case <-time.After(10 * time.Second):
		log.Critical("[Server] Failed to connect to RabbitMQ")
		os.Exit(1)
	}

	// Get a delivery channel from the connection
	log.Infof("[Server] Listening for deliveries on %s.#", s.ServiceName)
	deliveries, err := s.connection.Consume(s.ServiceName)
	if err != nil {
		log.Criticalf("[Server] [%s] Failed to consume from Rabbit", s.ServiceName)
	}

	// Handle deliveries
	for req := range deliveries {
		log.Infof("[Server] [%s] Received new delivery", s.ServiceName)
		go s.handleRequest(req)
	}

	log.Infof("Exiting")
	log.Flush()
}

func (s *AMQPServer) handleRequest(delivery amqp.Delivery) {

	endpointName := strings.Replace(delivery.RoutingKey, fmt.Sprintf("%s.", s.ServiceName), "", -1)
	endpoint := s.endpointRegistry.Get(endpointName)
	if endpoint == nil {
		log.Error("[Server] Endpoint not found, cannot handle request")
		s.respondWithError(delivery, errors.New("Endpoint not found"))
		return
	}
	req := NewAMQPRequest(&delivery)
	rsp, err := endpoint.HandleRequest(req)
	if err != nil {
		log.Errorf("[Server] Endpoint %s returned an error", endpointName)
		log.Error(err.Error())
	}
	body, err := proto.Marshal(rsp)
	if err != nil {
		log.Errorf("[Server] Failed to marshal response")
	}
	msg := amqp.Publishing{
		CorrelationId: delivery.CorrelationId,
		Timestamp:     time.Now().UTC(),
		Body:          body,
	}
	s.connection.Publish("", delivery.ReplyTo, msg)
}

// respondWithError to a delivery, with the provided error
func (s *AMQPServer) respondWithError(delivery amqp.Delivery, err error) {

	// Construct a return message with an error
	msg := amqp.Publishing{
		CorrelationId: delivery.CorrelationId,
		Timestamp:     time.Now().UTC(),
		Body:          []byte(err.Error()),
	}

	// Publish the error back to the client
	s.connection.Publish("", delivery.ReplyTo, msg)
}
<commit_msg>Moar comments<commit_after>package server

import (
	"errors"
	"fmt"
	"os"
	"strings"
	"time"

	log "github.com/cihub/seelog"
	"github.com/golang/protobuf/proto"
	"github.com/streadway/amqp"

	"github.com/vinceprignano/bunny/rabbit"
)

type AMQPServer struct {
	// this is the routing key prefix for all endpoints
	ServiceName        string
	ServiceDescription string
	endpointRegistry   *EndpointRegistry
	connection         *rabbit.RabbitConnection
}

func NewAMQPServer() Server {
	return &AMQPServer{
		endpointRegistry: NewEndpointRegistry(),
		connection:       rabbit.NewRabbitConnection(),
	}
}

func (s *AMQPServer) Name() string {
	if s == nil {
		return ""
	}
	return s.ServiceName
}

func (s *AMQPServer) Description() string {
	if s == nil {
		return ""
	}
	return s.ServiceDescription
}

func (s *AMQPServer) Initialise(c *Config) {
	s.ServiceName = c.Name
	s.ServiceDescription = c.Description
}

func (s *AMQPServer) RegisterEndpoint(endpoint Endpoint) {
	s.endpointRegistry.Register(endpoint)
}

func (s *AMQPServer) DeregisterEndpoint(endpointName string) {
	s.endpointRegistry.Deregister(endpointName)
}

// Run the server, connecting to our transport and serving requests
func (s *AMQPServer) Run() {

	// Connect to AMQP
	select {
	case <-s.connection.Init():
		log.Info("[Server] Connected to RabbitMQ")
	case <-time.After(10 * time.Second):
		log.Critical("[Server] Failed to connect to RabbitMQ")
		os.Exit(1)
	}

	// Get a delivery channel from the connection
	log.Infof("[Server] Listening for deliveries on %s.#", s.ServiceName)
	deliveries, err := s.connection.Consume(s.ServiceName)
	if err != nil {
		log.Criticalf("[Server] [%s] Failed to consume from Rabbit", s.ServiceName)
	}

	// Handle deliveries
	for req := range deliveries {
		log.Infof("[Server] [%s] Received new delivery", s.ServiceName)
		go s.handleRequest(req)
	}

	log.Infof("Exiting")
	log.Flush()
}

// handleRequest takes a delivery from AMQP, attempts to process it and return a response
func (s *AMQPServer) handleRequest(delivery amqp.Delivery) {

	// See if we have a matching endpoint for this request
	endpointName := strings.Replace(delivery.RoutingKey, fmt.Sprintf("%s.", s.ServiceName), "", -1)
	endpoint := s.endpointRegistry.Get(endpointName)
	if endpoint == nil {
		log.Error("[Server] Endpoint not found, cannot handle request")
		s.respondWithError(delivery, errors.New("Endpoint not found"))
		return
	}

	// Handle the delivery
	req := NewAMQPRequest(&delivery)
	rsp, err := endpoint.HandleRequest(req)
	if err != nil {
		log.Errorf("[Server] Endpoint %s returned an error", endpointName)
		log.Error(err.Error())
	}

	// Marshal the response
	body, err := proto.Marshal(rsp)
	if err != nil {
		log.Errorf("[Server] Failed to marshal response")
	}

	// Build return delivery, and publish
	msg := amqp.Publishing{
		CorrelationId: delivery.CorrelationId,
		Timestamp:     time.Now().UTC(),
		Body:          body,
	}
	s.connection.Publish("", delivery.ReplyTo, msg)
}

// respondWithError to a delivery, with the provided error
func (s *AMQPServer) respondWithError(delivery amqp.Delivery, err error) {

	// Construct a return message with an error
	msg := amqp.Publishing{
		CorrelationId: delivery.CorrelationId,
		Timestamp:     time.Now().UTC(),
		Body:          []byte(err.Error()),
	}

	// Publish the error back to the client
	s.connection.Publish("", delivery.ReplyTo, msg)
}
<|endoftext|>


<commit_before>package ole

import (
	"fmt"
	"testing"
)

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

	coInitialize()
	CoUninitialize()
}

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

	CoInitialize(0)
	CoUninitialize()
}

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

	CoInitialize(5)
	CoUninitialize()
}

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

	coInitializeEx(COINIT_MULTITHREADED)
	CoUninitialize()
}

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

	CoInitializeEx(0, COINIT_MULTITHREADED)
	CoUninitialize()
}

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

	CoInitializeEx(5, COINIT_MULTITHREADED)
	CoUninitialize()
}

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

	expected := &GUID{0x92498132, 0x4D1A, 0x4297, [8]byte{0x9B, 0x78, 0x9E, 0x2E, 0x4B, 0xA9, 0x9C, 0x07}}

	coInitialize()
	actual, err := CLSIDFromProgID("WMPNSSCI.NSSManager")
	CoUninitialize()

	if !IsEqualGUID(expected, actual) {
		t.Log(err)
		t.Log(fmt.Sprintf("Actual GUID: %+v\n", actual))
		t.Fail()
	}
}

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

	expected := &GUID{0x92498132, 0x4D1A, 0x4297, [8]byte{0x9B, 0x78, 0x9E, 0x2E, 0x4B, 0xA9, 0x9C, 0x07}}

	coInitialize()
	actual, err := CLSIDFromString("{92498132-4D1A-4297-9B78-9E2E4BA99C07}")
	CoUninitialize()

	if !IsEqualGUID(expected, actual) {
		t.Log(err)
		t.Log(fmt.Sprintf("Actual GUID: %+v\n", actual))
		t.Fail()
	}
}
<commit_msg>Add test for CreateInstance for making sure that the call works.<commit_after>package ole

import (
	"fmt"
	"testing"
)

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

	coInitialize()
	CoUninitialize()
}

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

	CoInitialize(0)
	CoUninitialize()
}

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

	CoInitialize(5)
	CoUninitialize()
}

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

	coInitializeEx(COINIT_MULTITHREADED)
	CoUninitialize()
}

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

	CoInitializeEx(0, COINIT_MULTITHREADED)
	CoUninitialize()
}

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

	CoInitializeEx(5, COINIT_MULTITHREADED)
	CoUninitialize()
}

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

	expected := &GUID{0x92498132, 0x4D1A, 0x4297, [8]byte{0x9B, 0x78, 0x9E, 0x2E, 0x4B, 0xA9, 0x9C, 0x07}}

	coInitialize()
	actual, err := CLSIDFromProgID("WMPNSSCI.NSSManager")
	CoUninitialize()

	if !IsEqualGUID(expected, actual) {
		t.Log(err)
		t.Log(fmt.Sprintf("Actual GUID: %+v\n", actual))
		t.Fail()
	}
}

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

	expected := &GUID{0x92498132, 0x4D1A, 0x4297, [8]byte{0x9B, 0x78, 0x9E, 0x2E, 0x4B, 0xA9, 0x9C, 0x07}}

	coInitialize()
	actual, err := CLSIDFromString("{92498132-4D1A-4297-9B78-9E2E4BA99C07}")
	CoUninitialize()

	if !IsEqualGUID(expected, actual) {
		t.Log(err)
		t.Log(fmt.Sprintf("Actual GUID: %+v\n", actual))
		t.Fail()
	}
}

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

	expected := &GUID{0x92498132, 0x4D1A, 0x4297, [8]byte{0x9B, 0x78, 0x9E, 0x2E, 0x4B, 0xA9, 0x9C, 0x07}}

	coInitialize()
	defer CoUninitialize()
	actual, err := CLSIDFromProgID("WMPNSSCI.NSSManager")

	if !IsEqualGUID(expected, actual) {
		t.Log(err)
		t.Log(fmt.Sprintf("Actual GUID: %+v\n", actual))
		t.Fail()
	}

	unknown, err := CreateInstance(actual, IID_IUnknown)
	if err != nil {
		t.Log(err)
		t.Fail()
	}
	unknown.Release()
}
<|endoftext|>