<commit_before>// Copyright 2018 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

package app

import (
	"errors"
	"net/http"
	"plugin"

	"github.com/issue9/web/dependency"
)

// PluginModuleName 插件中必须提供的变量名称。
// 根据此变量提供的数据进行初始化。
const PluginModuleName = "Module"

// 表示模块的类型。
const (
	ModuleTypeAll    ModuleType = iota
	ModuleTypeModule            // 默认的方式，即和代码一起编译
	ModuleTypePlugin            // 加载以 buildmode=plugin 方式编译的模块
)

// ModuleType 用以指定模块的类型。
type ModuleType int8

// Module 表示模块信息
type Module struct {
	Name        string
	Deps        []string
	Description string
	Routes      []*Route
	Type        ModuleType

	inits        []dependency.InitFunc
	buildHandler BuildHandler
}

// Route 表示模块信息中的路由信息
type Route struct {
	Path    string
	Handler http.Handler
	Methods []string
}

// Prefix 可以将具有统一前缀的路由项集中在一起操作。
//  p := srv.Prefix("/api")
//  p.Get("/users")  // 相当于 srv.Get("/api/users")
//  p.Get("/user/1") // 相当于 srv.Get("/api/user/1")
type Prefix struct {
	module *Module
	prefix string
}

// Modules 获取当前的所有模块信息
func (app *App) Modules() []*Module {
	return app.modules
}

// AddModule 注册一个新的模块。
func (app *App) AddModule(m *Module) *App {
	app.modules = append(app.modules, m)
	return app
}

// 加载配置文件中指定的所有插件
func (app *App) loadPlugins() error {
	for _, p := range app.config.Plugins {
		if err := app.loadPlugin(p); err != nil {
			return err
		}
	}

	return nil
}

func (app *App) loadPlugin(path string) error {
	p, err := plugin.Open(path)
	if err != nil {
		return err
	}

	symbol, err := p.Lookup("M")
	if err != nil {
		return err
	}

	module, ok := symbol.(*Module)
	if !ok {
		return errors.New("无法转换成 Module")
	}

	module.Type = ModuleTypePlugin
	app.AddModule(module)

	return nil
}

func (app *App) initDependency() error {
	dep := dependency.New()

	for _, module := range app.modules {
		dep.Add(module.Name, app.getInit(module), module.Deps...)
	}

	return dep.Init()
}

// 当 Module 的内容生成一个 dependency.InitFunc 函数
func (app *App) getInit(m *Module) dependency.InitFunc {
	return func() error {
		for _, init := range m.inits {
			if err := init(); err != nil {
				return err
			}
		}

		for _, r := range m.Routes {
			h := r.Handler
			if m.buildHandler != nil {
				h = m.buildHandler(h)
			}

			if err := app.router.Handle(r.Path, h, r.Methods...); err != nil {
				return err
			}
		}

		return nil
	}
}

// NewPlugin 声明一个新的模块，该模块以插件的形式提供。
//
// 需要将插件添加到配置文件中，才会在启动时，加载到系统中。
//
// name 模块名称，需要全局唯一；
// desc 模块的详细信息；
// deps 表示当前模块的依赖模块名称。
func NewPlugin(name, desc string, deps ...string) *Module {
	m := NewModule(name, desc, deps...)
	m.Type = ModuleTypePlugin
	return m
}

// NewModule 声明一个新的模块
//
// 仅作声明，并不会添加到系统中，需要通过 AddModule 时行添加。
//
// name 模块名称，需要全局唯一；
// desc 模块的详细信息；
// deps 表示当前模块的依赖模块名称，可以是插件中的模块名称。
func NewModule(name, desc string, deps ...string) *Module {
	return &Module{
		Name:        name,
		Deps:        deps,
		Description: desc,
		Type:        ModuleTypeModule,
		Routes:      make([]*Route, 0, 10),
		inits:       make([]dependency.InitFunc, 0, 5),
	}
}

// Prefix 声明一个 Prefix 实例。
func (m *Module) Prefix(prefix string) *Prefix {
	return &Prefix{
		module: m,
		prefix: prefix,
	}
}

// Module 返回关联的 Module 实全
func (p *Prefix) Module() *Module {
	return p.module
}

// SetHandler 为当前模块的所有路由添加的中间件。
//
// 多次调用，最后一次为准。
func (m *Module) SetHandler(f BuildHandler) {
	m.buildHandler = f
}

// AddInit 添加一个初始化函数
func (m *Module) AddInit(f dependency.InitFunc) *Module {
	m.inits = append(m.inits, f)
	return m
}

// Handle 添加一个路由项
func (m *Module) Handle(path string, h http.Handler, methods ...string) *Module {
	m.Routes = append(m.Routes, &Route{
		Methods: methods,
		Path:    path,
		Handler: h,
	})

	return m
}

// Get 指定一个 GET 请求
func (m *Module) Get(path string, h http.Handler) *Module {
	return m.Handle(path, h, http.MethodGet)
}

// Post 指定个 POST 请求处理
func (m *Module) Post(path string, h http.Handler) *Module {
	return m.Handle(path, h, http.MethodPost)
}

// Delete 指定个 Delete 请求处理
func (m *Module) Delete(path string, h http.Handler) *Module {
	return m.Handle(path, h, http.MethodDelete)
}

// Put 指定个 Put 请求处理
func (m *Module) Put(path string, h http.Handler) *Module {
	return m.Handle(path, h, http.MethodPut)
}

// Patch 指定个 Patch 请求处理
func (m *Module) Patch(path string, h http.Handler) *Module {
	return m.Handle(path, h, http.MethodPatch)
}

// HandleFunc 指定一个请求
func (m *Module) HandleFunc(path string, h func(w http.ResponseWriter, r *http.Request), methods ...string) *Module {
	return m.Handle(path, http.HandlerFunc(h), methods...)
}

// GetFunc 指定一个 GET 请求
func (m *Module) GetFunc(path string, h func(w http.ResponseWriter, r *http.Request)) *Module {
	return m.HandleFunc(path, h, http.MethodGet)
}

// PostFunc 指定一个 Post 请求
func (m *Module) PostFunc(path string, h func(w http.ResponseWriter, r *http.Request)) *Module {
	return m.HandleFunc(path, h, http.MethodPost)
}

// DeleteFunc 指定一个 Delete 请求
func (m *Module) DeleteFunc(path string, h func(w http.ResponseWriter, r *http.Request)) *Module {
	return m.HandleFunc(path, h, http.MethodDelete)
}

// PutFunc 指定一个 Put 请求
func (m *Module) PutFunc(path string, h func(w http.ResponseWriter, r *http.Request)) *Module {
	return m.HandleFunc(path, h, http.MethodPut)
}

// PatchFunc 指定一个 Patch 请求
func (m *Module) PatchFunc(path string, h func(w http.ResponseWriter, r *http.Request)) *Module {
	return m.HandleFunc(path, h, http.MethodPatch)
}

// Handle 添加路由项
func (p *Prefix) Handle(path string, h http.Handler, methods ...string) *Prefix {
	p.module.Handle(p.prefix+path, h, methods...)
	return p
}

// Get 指定一个 GET 请求
func (p *Prefix) Get(path string, h http.Handler) *Prefix {
	return p.Handle(path, h, http.MethodGet)
}

// Post 指定一个 Post 请求
func (p *Prefix) Post(path string, h http.Handler) *Prefix {
	return p.Handle(path, h, http.MethodPost)
}

// Delete 指定一个 Delete 请求
func (p *Prefix) Delete(path string, h http.Handler) *Prefix {
	return p.Handle(path, h, http.MethodDelete)
}

// Put 指定一个 Put 请求
func (p *Prefix) Put(pattern string, h http.Handler) *Prefix {
	return p.Handle(pattern, h, http.MethodPut)
}

// Patch 指定一个 Patch 请求
func (p *Prefix) Patch(pattern string, h http.Handler) *Prefix {
	return p.Handle(pattern, h, http.MethodPatch)
}

// HandleFunc 指定一个请求
func (p *Prefix) HandleFunc(path string, f http.HandlerFunc, methods ...string) *Prefix {
	return p.Handle(path, http.HandlerFunc(f), methods...)
}

// GetFunc 指定一个 Get 请求
func (p *Prefix) GetFunc(path string, f http.HandlerFunc) *Prefix {
	return p.HandleFunc(path, f, http.MethodGet)
}

// PutFunc 指定一个 Put 请求
func (p *Prefix) PutFunc(path string, f http.HandlerFunc) *Prefix {
	return p.HandleFunc(path, f, http.MethodPut)
}

// PostFunc 指定一个 Post 请求
func (p *Prefix) PostFunc(path string, f http.HandlerFunc) *Prefix {
	return p.HandleFunc(path, f, http.MethodPost)
}

// DeleteFunc 指定一个 Delete 请求
func (p *Prefix) DeleteFunc(path string, f http.HandlerFunc) *Prefix {
	return p.HandleFunc(path, f, http.MethodDelete)
}

// PatchFunc 指定一个 Patch 请求
func (p *Prefix) PatchFunc(path string, f http.HandlerFunc) *Prefix {
	return p.HandleFunc(path, f, http.MethodPatch)
}
<commit_msg>修正 loadPlugin 错误<commit_after>// Copyright 2018 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

package app

import (
	"errors"
	"net/http"
	"plugin"

	"github.com/issue9/web/dependency"
)

// PluginModuleName 插件中必须提供的变量名称。
// 根据此变量提供的数据进行初始化。
const PluginModuleName = "Module"

// 表示模块的类型。
const (
	ModuleTypeAll    ModuleType = iota
	ModuleTypeModule            // 默认的方式，即和代码一起编译
	ModuleTypePlugin            // 加载以 buildmode=plugin 方式编译的模块
)

// ModuleType 用以指定模块的类型。
type ModuleType int8

// Module 表示模块信息
type Module struct {
	Name        string
	Deps        []string
	Description string
	Routes      []*Route
	Type        ModuleType

	inits        []dependency.InitFunc
	buildHandler BuildHandler
}

// Route 表示模块信息中的路由信息
type Route struct {
	Path    string
	Handler http.Handler
	Methods []string
}

// Prefix 可以将具有统一前缀的路由项集中在一起操作。
//  p := srv.Prefix("/api")
//  p.Get("/users")  // 相当于 srv.Get("/api/users")
//  p.Get("/user/1") // 相当于 srv.Get("/api/user/1")
type Prefix struct {
	module *Module
	prefix string
}

// Modules 获取当前的所有模块信息
func (app *App) Modules() []*Module {
	return app.modules
}

// AddModule 注册一个新的模块。
func (app *App) AddModule(m *Module) *App {
	app.modules = append(app.modules, m)
	return app
}

// 加载配置文件中指定的所有插件
func (app *App) loadPlugins() error {
	for _, p := range app.config.Plugins {
		if err := app.loadPlugin(p); err != nil {
			return err
		}
	}

	return nil
}

func (app *App) loadPlugin(path string) error {
	p, err := plugin.Open(path)
	if err != nil {
		return err
	}

	symbol, err := p.Lookup(PluginModuleName)
	if err != nil {
		return err
	}

	module, ok := symbol.(*Module)
	if !ok {
		return errors.New("无法转换成 Module")
	}

	module.Type = ModuleTypePlugin
	app.AddModule(module)

	return nil
}

func (app *App) initDependency() error {
	dep := dependency.New()

	for _, module := range app.modules {
		dep.Add(module.Name, app.getInit(module), module.Deps...)
	}

	return dep.Init()
}

// 当 Module 的内容生成一个 dependency.InitFunc 函数
func (app *App) getInit(m *Module) dependency.InitFunc {
	return func() error {
		for _, init := range m.inits {
			if err := init(); err != nil {
				return err
			}
		}

		for _, r := range m.Routes {
			h := r.Handler
			if m.buildHandler != nil {
				h = m.buildHandler(h)
			}

			if err := app.router.Handle(r.Path, h, r.Methods...); err != nil {
				return err
			}
		}

		return nil
	}
}

// NewPlugin 声明一个新的模块，该模块以插件的形式提供。
//
// 需要将插件添加到配置文件中，才会在启动时，加载到系统中。
//
// name 模块名称，需要全局唯一；
// desc 模块的详细信息；
// deps 表示当前模块的依赖模块名称。
func NewPlugin(name, desc string, deps ...string) *Module {
	m := NewModule(name, desc, deps...)
	m.Type = ModuleTypePlugin
	return m
}

// NewModule 声明一个新的模块
//
// 仅作声明，并不会添加到系统中，需要通过 AddModule 时行添加。
//
// name 模块名称，需要全局唯一；
// desc 模块的详细信息；
// deps 表示当前模块的依赖模块名称，可以是插件中的模块名称。
func NewModule(name, desc string, deps ...string) *Module {
	return &Module{
		Name:        name,
		Deps:        deps,
		Description: desc,
		Type:        ModuleTypeModule,
		Routes:      make([]*Route, 0, 10),
		inits:       make([]dependency.InitFunc, 0, 5),
	}
}

// Prefix 声明一个 Prefix 实例。
func (m *Module) Prefix(prefix string) *Prefix {
	return &Prefix{
		module: m,
		prefix: prefix,
	}
}

// Module 返回关联的 Module 实全
func (p *Prefix) Module() *Module {
	return p.module
}

// SetHandler 为当前模块的所有路由添加的中间件。
//
// 多次调用，最后一次为准。
func (m *Module) SetHandler(f BuildHandler) {
	m.buildHandler = f
}

// AddInit 添加一个初始化函数
func (m *Module) AddInit(f dependency.InitFunc) *Module {
	m.inits = append(m.inits, f)
	return m
}

// Handle 添加一个路由项
func (m *Module) Handle(path string, h http.Handler, methods ...string) *Module {
	m.Routes = append(m.Routes, &Route{
		Methods: methods,
		Path:    path,
		Handler: h,
	})

	return m
}

// Get 指定一个 GET 请求
func (m *Module) Get(path string, h http.Handler) *Module {
	return m.Handle(path, h, http.MethodGet)
}

// Post 指定个 POST 请求处理
func (m *Module) Post(path string, h http.Handler) *Module {
	return m.Handle(path, h, http.MethodPost)
}

// Delete 指定个 Delete 请求处理
func (m *Module) Delete(path string, h http.Handler) *Module {
	return m.Handle(path, h, http.MethodDelete)
}

// Put 指定个 Put 请求处理
func (m *Module) Put(path string, h http.Handler) *Module {
	return m.Handle(path, h, http.MethodPut)
}

// Patch 指定个 Patch 请求处理
func (m *Module) Patch(path string, h http.Handler) *Module {
	return m.Handle(path, h, http.MethodPatch)
}

// HandleFunc 指定一个请求
func (m *Module) HandleFunc(path string, h func(w http.ResponseWriter, r *http.Request), methods ...string) *Module {
	return m.Handle(path, http.HandlerFunc(h), methods...)
}

// GetFunc 指定一个 GET 请求
func (m *Module) GetFunc(path string, h func(w http.ResponseWriter, r *http.Request)) *Module {
	return m.HandleFunc(path, h, http.MethodGet)
}

// PostFunc 指定一个 Post 请求
func (m *Module) PostFunc(path string, h func(w http.ResponseWriter, r *http.Request)) *Module {
	return m.HandleFunc(path, h, http.MethodPost)
}

// DeleteFunc 指定一个 Delete 请求
func (m *Module) DeleteFunc(path string, h func(w http.ResponseWriter, r *http.Request)) *Module {
	return m.HandleFunc(path, h, http.MethodDelete)
}

// PutFunc 指定一个 Put 请求
func (m *Module) PutFunc(path string, h func(w http.ResponseWriter, r *http.Request)) *Module {
	return m.HandleFunc(path, h, http.MethodPut)
}

// PatchFunc 指定一个 Patch 请求
func (m *Module) PatchFunc(path string, h func(w http.ResponseWriter, r *http.Request)) *Module {
	return m.HandleFunc(path, h, http.MethodPatch)
}

// Handle 添加路由项
func (p *Prefix) Handle(path string, h http.Handler, methods ...string) *Prefix {
	p.module.Handle(p.prefix+path, h, methods...)
	return p
}

// Get 指定一个 GET 请求
func (p *Prefix) Get(path string, h http.Handler) *Prefix {
	return p.Handle(path, h, http.MethodGet)
}

// Post 指定一个 Post 请求
func (p *Prefix) Post(path string, h http.Handler) *Prefix {
	return p.Handle(path, h, http.MethodPost)
}

// Delete 指定一个 Delete 请求
func (p *Prefix) Delete(path string, h http.Handler) *Prefix {
	return p.Handle(path, h, http.MethodDelete)
}

// Put 指定一个 Put 请求
func (p *Prefix) Put(pattern string, h http.Handler) *Prefix {
	return p.Handle(pattern, h, http.MethodPut)
}

// Patch 指定一个 Patch 请求
func (p *Prefix) Patch(pattern string, h http.Handler) *Prefix {
	return p.Handle(pattern, h, http.MethodPatch)
}

// HandleFunc 指定一个请求
func (p *Prefix) HandleFunc(path string, f http.HandlerFunc, methods ...string) *Prefix {
	return p.Handle(path, http.HandlerFunc(f), methods...)
}

// GetFunc 指定一个 Get 请求
func (p *Prefix) GetFunc(path string, f http.HandlerFunc) *Prefix {
	return p.HandleFunc(path, f, http.MethodGet)
}

// PutFunc 指定一个 Put 请求
func (p *Prefix) PutFunc(path string, f http.HandlerFunc) *Prefix {
	return p.HandleFunc(path, f, http.MethodPut)
}

// PostFunc 指定一个 Post 请求
func (p *Prefix) PostFunc(path string, f http.HandlerFunc) *Prefix {
	return p.HandleFunc(path, f, http.MethodPost)
}

// DeleteFunc 指定一个 Delete 请求
func (p *Prefix) DeleteFunc(path string, f http.HandlerFunc) *Prefix {
	return p.HandleFunc(path, f, http.MethodDelete)
}

// PatchFunc 指定一个 Patch ���求
func (p *Prefix) PatchFunc(path string, f http.HandlerFunc) *Prefix {
	return p.HandleFunc(path, f, http.MethodPatch)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"os/signal"
	"sync"
	"syscall"

	"github.com/docopt/docopt-go"
	"github.com/mushorg/glutton"
)

var usage = `
Usage:
    server -i <interface> [options]
    server -h | --help
Options:
    -i --interface=<iface>  Bind to this interface [default: eth0].
    -l --logpath=<path>     Log file path [default: /dev/null].
    -c --confpath=<path>    Configuration file path [default: config/].
    -d --debug=<boolean>    Enable debug mode [default: false].
    -h --help               Show this screen.
`

func onErrorExit(err error) {
	if err != nil {
		fmt.Printf("[glutton ] %+v\n", err)
		os.Exit(0)
	}
}

func onInterruptSignal(fn func()) {
	sig := make(chan os.Signal, 1)
	signal.Notify(sig, os.Interrupt, syscall.SIGHUP)

	go func() {
		<-sig
		fn()
	}()
}

func main() {
	fmt.Println(`
  _____ _       _   _
 / ____| |     | | | |
| |  __| |_   _| |_| |_ ___  _ __
| | |_ | | | | | __| __/ _ \| '_ \
| |__| | | |_| | |_| || (_) | | | |
 \_____|_|\__,_|\__|\__\___/|_| |_|

	`)

	args, err := docopt.Parse(usage, os.Args[1:], true, "", true)
	onErrorExit(err)

	gtn, err := glutton.New(args)
	onErrorExit(err)

	err = gtn.Init()
	onErrorExit(err)

	exitMtx := sync.RWMutex{}
	exit := func() {
		// See if there was a panic...
		if r := recover(); r != nil {
			fmt.Fprintln(os.Stderr, recover())
		}
		exitMtx.Lock()
		println() // make it look nice after the ^C
		fmt.Println("[glutton ] shutting down...")
		onErrorExit(gtn.Shutdown())
	}
	defer exit()

	onInterruptSignal(func() {
		exit()
		os.Exit(0)
	})

	onErrorExit(gtn.Start())
}
<commit_msg>Got this wrong, must be SIGTERM (#109)<commit_after>package main

import (
	"fmt"
	"os"
	"os/signal"
	"sync"
	"syscall"

	"github.com/docopt/docopt-go"
	"github.com/mushorg/glutton"
)

var usage = `
Usage:
    server -i <interface> [options]
    server -h | --help
Options:
    -i --interface=<iface>  Bind to this interface [default: eth0].
    -l --logpath=<path>     Log file path [default: /dev/null].
    -c --confpath=<path>    Configuration file path [default: config/].
    -d --debug=<boolean>    Enable debug mode [default: false].
    -h --help               Show this screen.
`

func onErrorExit(err error) {
	if err != nil {
		fmt.Printf("[glutton ] %+v\n", err)
		os.Exit(0)
	}
}

func onInterruptSignal(fn func()) {
	sig := make(chan os.Signal, 1)
	signal.Notify(sig, os.Interrupt, syscall.SIGTERM)

	go func() {
		<-sig
		fn()
	}()
}

func main() {
	fmt.Println(`
  _____ _       _   _
 / ____| |     | | | |
| |  __| |_   _| |_| |_ ___  _ __
| | |_ | | | | | __| __/ _ \| '_ \
| |__| | | |_| | |_| || (_) | | | |
 \_____|_|\__,_|\__|\__\___/|_| |_|

	`)

	args, err := docopt.Parse(usage, os.Args[1:], true, "", true)
	onErrorExit(err)

	gtn, err := glutton.New(args)
	onErrorExit(err)

	err = gtn.Init()
	onErrorExit(err)

	exitMtx := sync.RWMutex{}
	exit := func() {
		// See if there was a panic...
		if r := recover(); r != nil {
			fmt.Fprintln(os.Stderr, recover())
		}
		exitMtx.Lock()
		println() // make it look nice after the ^C
		fmt.Println("[glutton ] shutting down...")
		onErrorExit(gtn.Shutdown())
	}
	defer exit()

	onInterruptSignal(func() {
		exit()
		os.Exit(0)
	})

	onErrorExit(gtn.Start())
}
<|endoftext|>


<commit_before>package queue

import "testing"

func TestQueueLength(t *testing.T) {
	q := New()

	if q.Length() != 0 {
		t.Error("empty queue length not 0")
	}

	for i := 0; i < 1000; i++ {
		q.Add(i)
		if q.Length() != i+1 {
			t.Error("adding: queue with", i, "elements has length", q.Length())
		}
	}
	for i := 0; i < 1000; i++ {
		q.Remove()
		if q.Length() != 1000-i-1 {
			t.Error("removing: queue with", 1000-i-i, "elements has length", q.Length())
		}
	}
}

func TestQueueGet(t *testing.T) {
	q := New()

	for i := 0; i < 1000; i++ {
		q.Add(i)
		for j := 0; j < q.Length(); j++ {
			if q.Get(j).(int) != j {
				t.Errorf("index %d doesn't contain %d", j, j)
			}
		}
	}
}

func TestQueueGetOutOfRangePanics(t *testing.T) {
	q := New()

	q.Add(1)
	q.Add(2)
	q.Add(3)

	assertPanics(t, "should panic when negative index", func() {
		q.Get(-1)
	})

	assertPanics(t, "should panic when index greater than length", func() {
		q.Get(4)
	})
}

func TestQueuePeekOutOfRangePanics(t *testing.T) {
	q := New()

	assertPanics(t, "should panic when peeking empty queue", func() {
		q.Peek()
	})

	q.Add(1)
	q.Remove()

	assertPanics(t, "should panic when peeking emptied queue", func() {
		q.Peek()
	})
}

func TestQueueRemoveOutOfRangePanics(t *testing.T) {
	q := New()

	assertPanics(t, "should panic when removing empty queue", func() {
		q.Remove()
	})

	q.Add(1)
	q.Remove()

	assertPanics(t, "should panic when removing emptied queue", func() {
		q.Remove()
	})
}

func assertPanics(t *testing.T, name string, f func()) {
	defer func() {
		if r := recover(); r == nil {
			t.Errorf("%s: didn't panic as expected", name)
		} else {
			t.Logf("%s: got panic as expected: %v", name, r)
		}
	}()

	f()
}

// General warning: Go's benchmark utility (go test -bench .) increases the number of
// iterations until the benchmarks take a reasonable amount of time to run; memory usage
// is *NOT* considered. On my machine, these benchmarks hit around ~1GB before they've had
// enough, but if you have less than that available and start swapping, then all bets are off.

func BenchmarkQueueSerial(b *testing.B) {
	q := New()
	for i := 0; i < b.N; i++ {
		q.Add(nil)
	}
	for i := 0; i < b.N; i++ {
		q.Remove()
	}
}

func BenchmarkQueueGet(b *testing.B) {
	q := New()
	for i := 0; i < b.N; i++ {
		q.Add(i)
	}
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		q.Get(i)
	}
}

func BenchmarkQueueTickTock(b *testing.B) {
	q := New()
	for i := 0; i < b.N; i++ {
		q.Add(nil)
		q.Remove()
	}
}
<commit_msg>Add Peek() calls to the benchmark for more realism<commit_after>package queue

import "testing"

func TestQueueLength(t *testing.T) {
	q := New()

	if q.Length() != 0 {
		t.Error("empty queue length not 0")
	}

	for i := 0; i < 1000; i++ {
		q.Add(i)
		if q.Length() != i+1 {
			t.Error("adding: queue with", i, "elements has length", q.Length())
		}
	}
	for i := 0; i < 1000; i++ {
		q.Remove()
		if q.Length() != 1000-i-1 {
			t.Error("removing: queue with", 1000-i-i, "elements has length", q.Length())
		}
	}
}

func TestQueueGet(t *testing.T) {
	q := New()

	for i := 0; i < 1000; i++ {
		q.Add(i)
		for j := 0; j < q.Length(); j++ {
			if q.Get(j).(int) != j {
				t.Errorf("index %d doesn't contain %d", j, j)
			}
		}
	}
}

func TestQueueGetOutOfRangePanics(t *testing.T) {
	q := New()

	q.Add(1)
	q.Add(2)
	q.Add(3)

	assertPanics(t, "should panic when negative index", func() {
		q.Get(-1)
	})

	assertPanics(t, "should panic when index greater than length", func() {
		q.Get(4)
	})
}

func TestQueuePeekOutOfRangePanics(t *testing.T) {
	q := New()

	assertPanics(t, "should panic when peeking empty queue", func() {
		q.Peek()
	})

	q.Add(1)
	q.Remove()

	assertPanics(t, "should panic when peeking emptied queue", func() {
		q.Peek()
	})
}

func TestQueueRemoveOutOfRangePanics(t *testing.T) {
	q := New()

	assertPanics(t, "should panic when removing empty queue", func() {
		q.Remove()
	})

	q.Add(1)
	q.Remove()

	assertPanics(t, "should panic when removing emptied queue", func() {
		q.Remove()
	})
}

func assertPanics(t *testing.T, name string, f func()) {
	defer func() {
		if r := recover(); r == nil {
			t.Errorf("%s: didn't panic as expected", name)
		} else {
			t.Logf("%s: got panic as expected: %v", name, r)
		}
	}()

	f()
}

// General warning: Go's benchmark utility (go test -bench .) increases the number of
// iterations until the benchmarks take a reasonable amount of time to run; memory usage
// is *NOT* considered. On my machine, these benchmarks hit around ~1GB before they've had
// enough, but if you have less than that available and start swapping, then all bets are off.

func BenchmarkQueueSerial(b *testing.B) {
	q := New()
	for i := 0; i < b.N; i++ {
		q.Add(nil)
	}
	for i := 0; i < b.N; i++ {
		q.Peek()
		q.Remove()
	}
}

func BenchmarkQueueGet(b *testing.B) {
	q := New()
	for i := 0; i < b.N; i++ {
		q.Add(i)
	}
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		q.Get(i)
	}
}

func BenchmarkQueueTickTock(b *testing.B) {
	q := New()
	for i := 0; i < b.N; i++ {
		q.Add(nil)
		q.Peek()
		q.Remove()
	}
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package gotoolkit

import (
	"testing"
)

func TestEnqueue(t *testing.T) {
	queues := []Queue{new(ListQueue), new(SliceQueue)}

	for _, queue := range queues {
		queue.Enqueue("Test")

		if queue.Size() == 0 {
			t.Errorf("Incorrect result\ngot:  %d\nwant: %d", queue.Size(), 0)
		}
	}

}

func TestDequeue(t *testing.T) {
	queues := []Queue{new(ListQueue), new(SliceQueue)}

	for _, queue := range queues {
		queue.Enqueue("Test")
		item, err := queue.Dequeue()

		if err != nil {
			t.Errorf("Incorrect result\ngot:  %v\nwant: %v", err, nil)
		}

		if item != "Test" {
			t.Errorf("Incorrect result\ngot:  %s\nwant: %s", item, "Test")
		}

		if queue.Size() != 0 {
			t.Errorf("Incorrect result\ngot:  %d\nwant: %d", queue.Size(), 0)
		}
	}
}

func TestDequeueWithEmptyQueue(t *testing.T) {
	queues := []Queue{new(ListQueue), new(SliceQueue)}

	for _, queue := range queues {
		item, err := queue.Dequeue()
		want := "unable to dequeue element, queue is empty"

		if err.Error() != want {
			t.Errorf("Incorrect result\ngot:  %s\nwant: %s", err, want)
		}

		if item != nil {
			t.Errorf("Incorrect result\ngot:  %v\nwant: %v", item, nil)
		}

		if !queue.IsEmpty() {
			t.Errorf("Incorrect result\ngot:  %t\nwant: %t", queue.IsEmpty(), true)
		}
	}
}

func TestPeekQueue(t *testing.T) {
	queues := []Queue{new(ListQueue), new(SliceQueue)}

	for _, queue := range queues {
		queue.Enqueue("Test")

		item, err := queue.Peek()

		if err != nil {
			t.Errorf("Incorrect result\ngot:  %v\nwant: %v", err, nil)
		}

		if item != "Test" {
			t.Errorf("Incorrect result\ngot:  %s\nwant: %s", item, "Test")
		}

		if queue.Size() != 1 {
			t.Errorf("Incorrect result\ngot:  %d\nwant: %d", queue.Size(), 1)
		}
	}
}
<commit_msg>Tests enqueuing multiple elements<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package gotoolkit

import (
	"testing"
)

func TestEnqueue(t *testing.T) {
	queues := []Queue{new(ListQueue), new(SliceQueue)}

	for _, queue := range queues {
		queue.Enqueue("Test")

		if queue.Size() == 0 {
			t.Errorf("Incorrect result\ngot:  %d\nwant: %d", queue.Size(), 0)
		}
	}

}

func TestDequeue(t *testing.T) {
	queues := []Queue{new(ListQueue), new(SliceQueue)}

	for _, queue := range queues {
		queue.Enqueue("Test1")
		queue.Enqueue("Test2")
		queue.Enqueue("Test3")
		item, err := queue.Dequeue()

		if err != nil {
			t.Errorf("Incorrect result\ngot:  %v\nwant: %v", err, nil)
		}

		if item != "Test1" {
			t.Errorf("Incorrect result\ngot:  %s\nwant: %s", item, "Test1")
		}

		if queue.Size() != 2 {
			t.Errorf("Incorrect result\ngot:  %d\nwant: %d", queue.Size(), 2)
		}
	}
}

func TestDequeueWithEmptyQueue(t *testing.T) {
	queues := []Queue{new(ListQueue), new(SliceQueue)}

	for _, queue := range queues {
		item, err := queue.Dequeue()
		want := "unable to dequeue element, queue is empty"

		if err.Error() != want {
			t.Errorf("Incorrect result\ngot:  %s\nwant: %s", err, want)
		}

		if item != nil {
			t.Errorf("Incorrect result\ngot:  %v\nwant: %v", item, nil)
		}

		if !queue.IsEmpty() {
			t.Errorf("Incorrect result\ngot:  %t\nwant: %t", queue.IsEmpty(), true)
		}
	}
}

func TestPeekQueue(t *testing.T) {
	queues := []Queue{new(ListQueue), new(SliceQueue)}

	for _, queue := range queues {
		queue.Enqueue("Test")

		item, err := queue.Peek()

		if err != nil {
			t.Errorf("Incorrect result\ngot:  %v\nwant: %v", err, nil)
		}

		if item != "Test" {
			t.Errorf("Incorrect result\ngot:  %s\nwant: %s", item, "Test")
		}

		if queue.Size() != 1 {
			t.Errorf("Incorrect result\ngot:  %d\nwant: %d", queue.Size(), 1)
		}
	}
}
<|endoftext|>


<commit_before>package tchannel_test

import (
	"sync"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	. "github.com/uber/tchannel-go"
	"github.com/uber/tchannel-go/raw"
	"github.com/uber/tchannel-go/testutils"
)

func TestRelay(t *testing.T) {
	relay, err := NewChannel("relay", &ChannelOptions{
		RelayHosts: NewSimpleRelayHosts(map[string][]string{}),
	})
	require.NoError(t, err, "Failed to create a relay channel.")
	require.NoError(t, relay.ListenAndServe("127.0.0.1:0"), "Relay failed to listen.")

	data := []byte("fake-body")

	server := testutils.NewServer(t, testutils.NewOpts().SetServiceName("test"))
	server.Register(raw.Wrap(newTestHandler(t)), "echo")
	relay.RelayHosts().(*SimpleRelayHosts).Add("test", server.PeerInfo().HostPort)

	client := testutils.NewClient(t, nil)
	client.Peers().Add(relay.PeerInfo().HostPort)

	var wg sync.WaitGroup
	wg.Add(1)

	go func(c *Channel) {
		sc := client.GetSubChannel("test")
		ctx, cancel := NewContext(time.Second)
		defer cancel()

		arg2, arg3, _, err := raw.CallSC(ctx, sc, "echo", []byte("fake-header"), data)
		t.Log(string(arg3))
		require.NoError(t, err, "Relayed call failed.")
		assert.Equal(t, "fake-header", string(arg2), "Header was mangled during relay.")
		assert.Equal(t, "fake-body", string(arg3), "Body was mangled during relay.")

		wg.Done()
	}(client)

	wg.Wait()
	client.Close()
	relay.Close()
	server.Close()
}
<commit_msg>Use defer to clean up relay test teardown<commit_after>package tchannel_test

import (
	"sync"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	. "github.com/uber/tchannel-go"
	"github.com/uber/tchannel-go/raw"
	"github.com/uber/tchannel-go/testutils"
)

func TestRelay(t *testing.T) {
	relay, err := NewChannel("relay", &ChannelOptions{
		RelayHosts: NewSimpleRelayHosts(map[string][]string{}),
	})
	require.NoError(t, err, "Failed to create a relay channel.")
	defer relay.Close()
	require.NoError(t, relay.ListenAndServe("127.0.0.1:0"), "Relay failed to listen.")

	data := []byte("fake-body")

	server := testutils.NewServer(t, testutils.NewOpts().SetServiceName("test"))
	defer server.Close()
	server.Register(raw.Wrap(newTestHandler(t)), "echo")
	relay.RelayHosts().(*SimpleRelayHosts).Add("test", server.PeerInfo().HostPort)

	client := testutils.NewClient(t, nil)
	defer client.Close()
	client.Peers().Add(relay.PeerInfo().HostPort)

	var wg sync.WaitGroup
	wg.Add(1)

	go func(c *Channel) {
		sc := client.GetSubChannel("test")
		ctx, cancel := NewContext(time.Second)
		defer cancel()

		arg2, arg3, _, err := raw.CallSC(ctx, sc, "echo", []byte("fake-header"), data)
		t.Log(string(arg3))
		require.NoError(t, err, "Relayed call failed.")
		assert.Equal(t, "fake-header", string(arg2), "Header was mangled during relay.")
		assert.Equal(t, "fake-body", string(arg3), "Body was mangled during relay.")

		wg.Done()
	}(client)

	wg.Wait()
}
<|endoftext|>


<commit_before>package data

import (
	"bytes"
	"crypto/sha512"
	"fmt"
)

type NodeIndex uint64

func (i *NodeIndex) Previous() *NodeIndex {
	switch {
	case i == nil:
		return nil
	case *i == 0:
		return nil
	default:
		prev := *i - 1
		return &prev
	}
}

func (i *NodeIndex) Next() *NodeIndex {
	if i == nil {
		return nil
	}
	next := *i + 1
	return &next
}

func LedgerIndex(le LedgerEntry) (*Hash256, error) {
	switch v := le.(type) {
	case *AccountRoot:
		return GetAccountRootIndex(*v.Account)
	case *RippleState:
		return GetRippleStateIndex(v.LowLimit.Issuer, v.HighLimit.Issuer, v.Balance.Currency)
	case *Offer:
		return GetOfferIndex(*v.Account, *v.Sequence)
	case *LedgerHashes:
		return GetLedgerHashIndex()
	case *Directory:
		return GetDirectoryNodeIndex(*v.RootIndex, v.IndexPrevious.Next())
	default:
		return nil, fmt.Errorf("Unknown LedgerEntry")
	}
}

func GetAccountRootIndex(account Account) (*Hash256, error) {
	return buildIndex([]interface{}{NS_ACCOUNT, account.Bytes()})
}

func GetOfferIndex(account Account, sequence uint32) (*Hash256, error) {
	return buildIndex([]interface{}{NS_OFFER, account.Bytes(), sequence})
}

func GetRippleStateIndex(a, b Account, c Currency) (*Hash256, error) {
	if bytes.Compare(a.Bytes(), b.Bytes()) < 0 {
		return buildIndex([]interface{}{NS_RIPPLE_STATE, a.Bytes(), b.Bytes(), c.Bytes()})
	}
	return buildIndex([]interface{}{NS_RIPPLE_STATE, b.Bytes(), a.Bytes(), c.Bytes()})
}

func GetDirectoryNodeIndex(root Hash256, index *NodeIndex) (*Hash256, error) {
	if index == nil {
		return &root, nil
	}
	return buildIndex([]interface{}{NS_DIRECTORY_NODE, root, *index})
}

func GetOwnerDirectoryIndex(account Account) (*Hash256, error) {
	return buildIndex([]interface{}{NS_OWNER_DIRECTORY, account.Bytes()})
}

func GetBookIndex(paysCurrency, getsCurrency Hash160, paysIssuer, getsIssuer Hash160) (*Hash256, error) {
	//TODO: change types to Currency and Account
	index, err := buildIndex([]interface{}{NS_BOOK_DIRECTORY, paysCurrency.Bytes(), getsCurrency.Bytes(), paysCurrency.Bytes(), getsCurrency.Bytes()})
	if err != nil {
		return nil, err
	}
	var zero [8]byte
	copy(index[24:], zero[:])
	return index, nil
}

func GetFeeIndex() (*Hash256, error) {
	return buildIndex([]interface{}{NS_FEE})
}

func GetAmendmentsIndex() (*Hash256, error) {
	return buildIndex([]interface{}{NS_AMENDMENT})
}

func GetLedgerHashIndex() (*Hash256, error) {
	return buildIndex([]interface{}{NS_SKIP_LIST})
}

func GetPreviousLedgerHashIndex(sequence uint32) (*Hash256, error) {
	return buildIndex([]interface{}{NS_SKIP_LIST, sequence >> 16})
}

func buildIndex(items []interface{}) (*Hash256, error) {
	index := sha512.New()
	for _, item := range items {
		if err := write(index, item); err != nil {
			return nil, err
		}
	}
	return NewHash256(index.Sum(nil)[:32])
}
<commit_msg>NodeIndex overflow<commit_after>package data

import (
	"bytes"
	"crypto/sha512"
	"fmt"
	"math"
)

type NodeIndex uint64

func (i *NodeIndex) Previous() *NodeIndex {
	if i == nil || *i == 0 {
		return nil
	}
	prev := *i - 1
	return &prev
}

func (i *NodeIndex) Next() *NodeIndex {
	if i == nil || *i == math.MaxUint64 {
		return nil
	}
	next := *i + 1
	return &next
}

func LedgerIndex(le LedgerEntry) (*Hash256, error) {
	switch v := le.(type) {
	case *AccountRoot:
		return GetAccountRootIndex(*v.Account)
	case *RippleState:
		return GetRippleStateIndex(v.LowLimit.Issuer, v.HighLimit.Issuer, v.Balance.Currency)
	case *Offer:
		return GetOfferIndex(*v.Account, *v.Sequence)
	case *LedgerHashes:
		return GetLedgerHashIndex()
	case *Directory:
		return GetDirectoryNodeIndex(*v.RootIndex, v.IndexPrevious.Next())
	default:
		return nil, fmt.Errorf("Unknown LedgerEntry")
	}
}

func GetAccountRootIndex(account Account) (*Hash256, error) {
	return buildIndex([]interface{}{NS_ACCOUNT, account.Bytes()})
}

func GetOfferIndex(account Account, sequence uint32) (*Hash256, error) {
	return buildIndex([]interface{}{NS_OFFER, account.Bytes(), sequence})
}

func GetRippleStateIndex(a, b Account, c Currency) (*Hash256, error) {
	if bytes.Compare(a.Bytes(), b.Bytes()) < 0 {
		return buildIndex([]interface{}{NS_RIPPLE_STATE, a.Bytes(), b.Bytes(), c.Bytes()})
	}
	return buildIndex([]interface{}{NS_RIPPLE_STATE, b.Bytes(), a.Bytes(), c.Bytes()})
}

func GetDirectoryNodeIndex(root Hash256, index *NodeIndex) (*Hash256, error) {
	if index == nil {
		return &root, nil
	}
	return buildIndex([]interface{}{NS_DIRECTORY_NODE, root, *index})
}

func GetOwnerDirectoryIndex(account Account) (*Hash256, error) {
	return buildIndex([]interface{}{NS_OWNER_DIRECTORY, account.Bytes()})
}

func GetBookIndex(paysCurrency, getsCurrency Hash160, paysIssuer, getsIssuer Hash160) (*Hash256, error) {
	//TODO: change types to Currency and Account
	index, err := buildIndex([]interface{}{NS_BOOK_DIRECTORY, paysCurrency.Bytes(), getsCurrency.Bytes(), paysCurrency.Bytes(), getsCurrency.Bytes()})
	if err != nil {
		return nil, err
	}
	var zero [8]byte
	copy(index[24:], zero[:])
	return index, nil
}

func GetFeeIndex() (*Hash256, error) {
	return buildIndex([]interface{}{NS_FEE})
}

func GetAmendmentsIndex() (*Hash256, error) {
	return buildIndex([]interface{}{NS_AMENDMENT})
}

func GetLedgerHashIndex() (*Hash256, error) {
	return buildIndex([]interface{}{NS_SKIP_LIST})
}

func GetPreviousLedgerHashIndex(sequence uint32) (*Hash256, error) {
	return buildIndex([]interface{}{NS_SKIP_LIST, sequence >> 16})
}

func buildIndex(items []interface{}) (*Hash256, error) {
	index := sha512.New()
	for _, item := range items {
		if err := write(index, item); err != nil {
			return nil, err
		}
	}
	return NewHash256(index.Sum(nil)[:32])
}
<|endoftext|>


<commit_before>package kestrel

import (
	"fmt"
	"strconv"
	"strings"

	"github.com/alindeman/go-kestrel"
)

const (
	queue      = "test"
	bufferSize = 5
)

type KestrelPeer struct {
	client   *kestrel.Client
	messages chan []byte
	send     chan []byte
	errors   chan error
	done     chan bool
	flush    chan bool
}

func NewKestrelPeer(host string) (*KestrelPeer, error) {
	addrAndPort := strings.Split(host, ":")
	if len(addrAndPort) < 2 {
		return nil, fmt.Errorf("Invalid host: %s", host)
	}

	port, err := strconv.Atoi(addrAndPort[1])
	if err != nil {
		return nil, err
	}

	client := kestrel.NewClient(addrAndPort[0], port)
	if err := client.FlushAllQueues(); err != nil {
		client.Close()
		return nil, err
	}

	return &KestrelPeer{
		client:   client,
		messages: make(chan []byte, 10000),
		send:     make(chan []byte),
		errors:   make(chan error),
		done:     make(chan bool, 1),
		flush:    make(chan bool),
	}, nil
}

func (k *KestrelPeer) Subscribe() error {
	go func() {
		for {
			// TODO: Probably tweak the max items number.
			items, err := k.client.Get(queue, 500, 0, 0)
			if err != nil {
				// Broker shutdown.
				return
			}
			for _, item := range items {
				k.messages <- item.Data
			}
		}
	}()
	return nil
}

func (k *KestrelPeer) Recv() ([]byte, error) {
	return <-k.messages, nil
}

func (k *KestrelPeer) Send() chan<- []byte {
	return k.send
}

func (k *KestrelPeer) Errors() <-chan error {
	return k.errors
}

func (k *KestrelPeer) Setup() {
	buffer := make([][]byte, bufferSize)
	go func() {
		i := 0
		for {
			select {
			case msg := <-k.send:
				buffer[i] = msg
				i++
				if i == bufferSize {
					if _, err := k.client.Put(queue, buffer); err != nil {
						k.errors <- err
					}
					i = 0
				}
			case <-k.done:
				if i > 0 {
					if _, err := k.client.Put(queue, buffer[0:i]); err != nil {
						k.errors <- err
					}
				}
				k.flush <- true
				return
			}
		}
	}()
}

func (k *KestrelPeer) Teardown() {
	k.done <- true
	<-k.flush
	k.client.Close()
}
<commit_msg>Fix deadlock bug<commit_after>package kestrel

import (
	"fmt"
	"strconv"
	"strings"

	"github.com/alindeman/go-kestrel"
)

const (
	queue      = "test"
	bufferSize = 10
)

type KestrelPeer struct {
	client     *kestrel.Client
	messages   chan []byte
	send       chan []byte
	errors     chan error
	done       chan bool
	flush      chan bool
	subscriber bool
}

func NewKestrelPeer(host string) (*KestrelPeer, error) {
	addrAndPort := strings.Split(host, ":")
	if len(addrAndPort) < 2 {
		return nil, fmt.Errorf("Invalid host: %s", host)
	}

	port, err := strconv.Atoi(addrAndPort[1])
	if err != nil {
		return nil, err
	}

	client := kestrel.NewClient(addrAndPort[0], port)
	if err := client.FlushAllQueues(); err != nil {
		client.Close()
		return nil, err
	}

	return &KestrelPeer{
		client:   client,
		messages: make(chan []byte, 10000),
		send:     make(chan []byte),
		errors:   make(chan error, 1),
		done:     make(chan bool, 1),
		flush:    make(chan bool),
	}, nil
}

func (k *KestrelPeer) Subscribe() error {
	k.subscriber = true
	go func() {
		for {
			// TODO: Probably tweak the max items number.
			items, err := k.client.Get(queue, 500, 0, 0)
			if err != nil {
				// Broker shutdown.
				return
			}
			for _, item := range items {
				k.messages <- item.Data
			}
		}
	}()
	return nil
}

func (k *KestrelPeer) Recv() ([]byte, error) {
	return <-k.messages, nil
}

func (k *KestrelPeer) Send() chan<- []byte {
	return k.send
}

func (k *KestrelPeer) Errors() <-chan error {
	return k.errors
}

func (k *KestrelPeer) Setup() {
	buffer := make([][]byte, bufferSize)
	go func() {
		i := 0
		for {
			select {
			case msg := <-k.send:
				buffer[i] = msg
				i++
				if i == bufferSize {
					if _, err := k.client.Put(queue, buffer); err != nil {
						k.errors <- err
					}
					i = 0
				}
			case <-k.done:
				if i > 0 {
					if _, err := k.client.Put(queue, buffer[0:i]); err != nil {
						k.errors <- err
					}
				}
				k.flush <- true
				return
			}
		}
	}()
}

func (k *KestrelPeer) Teardown() {
	k.done <- true
	if !k.subscriber {
		<-k.flush
	}
	k.client.Close()
}
<|endoftext|>


<commit_before>// Copyright (c) Alex Ellis 2017. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

package inttests

import (
	"encoding/json"
	"net/http"
	"strings"
	"testing"

	"github.com/openfaas/faas/gateway/requests"
)

func createFunction(request requests.CreateFunctionRequest) (string, int, error) {
	marshalled, _ := json.Marshal(request)
	return fireRequest("http://localhost:8080/system/functions", http.MethodPost, string(marshalled))
}

func deleteFunction(name string) (string, int, error) {
	marshalled, _ := json.Marshal(requests.DeleteFunctionRequest{name})
	return fireRequest("http://localhost:8080/system/functions", http.MethodDelete, string(marshalled))
}

func TestCreate_ValidRequest(t *testing.T) {
	request := requests.CreateFunctionRequest{
		Service:    "test_resizer",
		Image:      "functions/resizer",
		Network:    "func_functions",
		EnvProcess: "",
	}

	_, code, err := createFunction(request)

	if err != nil {
		t.Log(err)
		t.Fail()
	}

	expectedErrorCode := http.StatusOK
	if code != expectedErrorCode {
		t.Errorf("Got HTTP code: %d, want %d\n", code, expectedErrorCode)
		return
	}

	deleteFunction("test_resizer")
}

func TestCreate_InvalidImage(t *testing.T) {
	request := requests.CreateFunctionRequest{
		Service:    "test_resizer",
		Image:      "a b c",
		Network:    "func_functions",
		EnvProcess: "",
	}

	body, code, err := createFunction(request)

	if err != nil {
		t.Log(err)
		t.Fail()
	}

	expectedErrorCode := http.StatusBadRequest
	if code != expectedErrorCode {
		t.Errorf("Got HTTP code: %d, want %d\n", code, expectedErrorCode)
		return
	}

	expectedErrorSlice := "is not a valid repository/tag"
	if !strings.Contains(body, expectedErrorSlice) {
		t.Errorf("Error message %s does not contain: %s\n", body, expectedErrorSlice)
		return
	}
}

func TestCreate_InvalidNetwork(t *testing.T) {
	request := requests.CreateFunctionRequest{
		Service:    "test_resizer",
		Image:      "functions/resizer",
		Network:    "non_existent_network",
		EnvProcess: "",
	}

	body, code, err := createFunction(request)

	if err != nil {
		t.Log(err)
		t.Fail()
	}

	expectedErrorCode := http.StatusBadRequest
	if code != expectedErrorCode {
		t.Errorf("Got HTTP code: %d, want %d\n", code, expectedErrorCode)
		return
	}

	expectedErrorSlice := "network non_existent_network not found"
	if !strings.Contains(body, expectedErrorSlice) {
		t.Errorf("Error message %s does not contain: %s\n", body, expectedErrorSlice)
		return
	}
}

func TestCreate_InvalidJson(t *testing.T) {
	reqBody := `not json`
	_, code, err := fireRequest("http://localhost:8080/system/functions", http.MethodPost, reqBody)

	if err != nil {
		t.Log(err)
		t.Fail()
	}

	if code != http.StatusBadRequest {
		t.Errorf("Got HTTP code: %d, want %d\n", code, http.StatusBadRequest)
	}
}
<commit_msg>Update integration test<commit_after>// Copyright (c) Alex Ellis 2017. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

package inttests

import (
	"encoding/json"
	"net/http"
	"strings"
	"testing"

	"github.com/openfaas/faas/gateway/requests"
)

func createFunction(request requests.CreateFunctionRequest) (string, int, error) {
	marshalled, _ := json.Marshal(request)
	return fireRequest("http://localhost:8080/system/functions", http.MethodPost, string(marshalled))
}

func deleteFunction(name string) (string, int, error) {
	marshalled, _ := json.Marshal(requests.DeleteFunctionRequest{name})
	return fireRequest("http://localhost:8080/system/functions", http.MethodDelete, string(marshalled))
}

func TestCreate_ValidRequest(t *testing.T) {
	request := requests.CreateFunctionRequest{
		Service:    "test_resizer",
		Image:      "functions/resizer",
		Network:    "func_functions",
		EnvProcess: "",
	}

	_, code, err := createFunction(request)

	if err != nil {
		t.Log(err)
		t.Fail()
	}

	expectedErrorCode := http.StatusAccepted
	if code != expectedErrorCode {
		t.Errorf("Got HTTP code: %d, want %d\n", code, expectedErrorCode)
		return
	}

	deleteFunction("test_resizer")
}

func TestCreate_InvalidImage(t *testing.T) {
	request := requests.CreateFunctionRequest{
		Service:    "test_resizer",
		Image:      "a b c",
		Network:    "func_functions",
		EnvProcess: "",
	}

	body, code, err := createFunction(request)

	if err != nil {
		t.Log(err)
		t.Fail()
	}

	expectedErrorCode := http.StatusBadRequest
	if code != expectedErrorCode {
		t.Errorf("Got HTTP code: %d, want %d\n", code, expectedErrorCode)
		return
	}

	expectedErrorSlice := "is not a valid repository/tag"
	if !strings.Contains(body, expectedErrorSlice) {
		t.Errorf("Error message %s does not contain: %s\n", body, expectedErrorSlice)
		return
	}
}

func TestCreate_InvalidNetwork(t *testing.T) {
	request := requests.CreateFunctionRequest{
		Service:    "test_resizer",
		Image:      "functions/resizer",
		Network:    "non_existent_network",
		EnvProcess: "",
	}

	body, code, err := createFunction(request)

	if err != nil {
		t.Log(err)
		t.Fail()
	}

	expectedErrorCode := http.StatusBadRequest
	if code != expectedErrorCode {
		t.Errorf("Got HTTP code: %d, want %d\n", code, expectedErrorCode)
		return
	}

	expectedErrorSlice := "network non_existent_network not found"
	if !strings.Contains(body, expectedErrorSlice) {
		t.Errorf("Error message %s does not contain: %s\n", body, expectedErrorSlice)
		return
	}
}

func TestCreate_InvalidJson(t *testing.T) {
	reqBody := `not json`
	_, code, err := fireRequest("http://localhost:8080/system/functions", http.MethodPost, reqBody)

	if err != nil {
		t.Log(err)
		t.Fail()
	}

	if code != http.StatusBadRequest {
		t.Errorf("Got HTTP code: %d, want %d\n", code, http.StatusBadRequest)
	}
}
<|endoftext|>


<commit_before>package image

import (
	"encoding/json"
	"errors"
	"io"
	"time"

	"github.com/docker/docker/api/types/container"
	"github.com/opencontainers/go-digest"
)

// ID is the content-addressable ID of an image.
type ID digest.Digest

func (id ID) String() string {
	return id.Digest().String()
}

// Digest converts ID into a digest
func (id ID) Digest() digest.Digest {
	return digest.Digest(id)
}

// IDFromDigest creates an ID from a digest
func IDFromDigest(digest digest.Digest) ID {
	return ID(digest)
}

// V1Image stores the V1 image configuration.
type V1Image struct {
	// ID is a unique 64 character identifier of the image
	ID string `json:"id,omitempty"`
	// Parent is the ID of the parent image
	Parent string `json:"parent,omitempty"`
	// Comment is the commit message that was set when committing the image
	Comment string `json:"comment,omitempty"`
	// Created is the timestamp at which the image was created
	Created time.Time `json:"created"`
	// Container is the id of the container used to commit
	Container string `json:"container,omitempty"`
	// ContainerConfig is the configuration of the container that is committed into the image
	ContainerConfig container.Config `json:"container_config,omitempty"`
	// DockerVersion specifies the version of Docker that was used to build the image
	DockerVersion string `json:"docker_version,omitempty"`
	// Author is the name of the author that was specified when committing the image
	Author string `json:"author,omitempty"`
	// Config is the configuration of the container received from the client
	Config *container.Config `json:"config,omitempty"`
	// Architecture is the hardware that the image is build and runs on
	Architecture string `json:"architecture,omitempty"`
	// OS is the operating system used to build and run the image
	OS string `json:"os,omitempty"`
	// Size is the total size of the image including all layers it is composed of
	Size int64 `json:",omitempty"`
}

// Image stores the image configuration
type Image struct {
	V1Image
	Parent     ID        `json:"parent,omitempty"`
	RootFS     *RootFS   `json:"rootfs,omitempty"`
	History    []History `json:"history,omitempty"`
	OSVersion  string    `json:"os.version,omitempty"`
	OSFeatures []string  `json:"os.features,omitempty"`

	// rawJSON caches the immutable JSON associated with this image.
	rawJSON []byte

	// computedID is the ID computed from the hash of the image config.
	// Not to be confused with the legacy V1 ID in V1Image.
	computedID ID
}

// RawJSON returns the immutable JSON associated with the image.
func (img *Image) RawJSON() []byte {
	return img.rawJSON
}

// ID returns the image's content-addressable ID.
func (img *Image) ID() ID {
	return img.computedID
}

// ImageID stringifies ID.
func (img *Image) ImageID() string {
	return img.ID().String()
}

// RunConfig returns the image's container config.
func (img *Image) RunConfig() *container.Config {
	return img.Config
}

// MarshalJSON serializes the image to JSON. It sorts the top-level keys so
// that JSON that's been manipulated by a push/pull cycle with a legacy
// registry won't end up with a different key order.
func (img *Image) MarshalJSON() ([]byte, error) {
	type MarshalImage Image

	pass1, err := json.Marshal(MarshalImage(*img))
	if err != nil {
		return nil, err
	}

	var c map[string]*json.RawMessage
	if err := json.Unmarshal(pass1, &c); err != nil {
		return nil, err
	}
	return json.Marshal(c)
}

// History stores build commands that were used to create an image
type History struct {
	// Created is the timestamp at which the image was created
	Created time.Time `json:"created"`
	// Author is the name of the author that was specified when committing the image
	Author string `json:"author,omitempty"`
	// CreatedBy keeps the Dockerfile command used while building the image
	CreatedBy string `json:"created_by,omitempty"`
	// Comment is the commit message that was set when committing the image
	Comment string `json:"comment,omitempty"`
	// EmptyLayer is set to true if this history item did not generate a
	// layer. Otherwise, the history item is associated with the next
	// layer in the RootFS section.
	EmptyLayer bool `json:"empty_layer,omitempty"`
}

// Exporter provides interface for loading and saving images
type Exporter interface {
	Load(io.ReadCloser, io.Writer, bool) error
	// TODO: Load(net.Context, io.ReadCloser, <- chan StatusMessage) error
	Save([]string, io.Writer) error
}

// NewFromJSON creates an Image configuration from json.
func NewFromJSON(src []byte) (*Image, error) {
	img := &Image{}

	if err := json.Unmarshal(src, img); err != nil {
		return nil, err
	}
	if img.RootFS == nil {
		return nil, errors.New("invalid image JSON, no RootFS key")
	}

	img.rawJSON = src

	return img, nil
}
<commit_msg>Fixing a typo in spelling<commit_after>package image

import (
	"encoding/json"
	"errors"
	"io"
	"time"

	"github.com/docker/docker/api/types/container"
	"github.com/opencontainers/go-digest"
)

// ID is the content-addressable ID of an image.
type ID digest.Digest

func (id ID) String() string {
	return id.Digest().String()
}

// Digest converts ID into a digest
func (id ID) Digest() digest.Digest {
	return digest.Digest(id)
}

// IDFromDigest creates an ID from a digest
func IDFromDigest(digest digest.Digest) ID {
	return ID(digest)
}

// V1Image stores the V1 image configuration.
type V1Image struct {
	// ID is a unique 64 character identifier of the image
	ID string `json:"id,omitempty"`
	// Parent is the ID of the parent image
	Parent string `json:"parent,omitempty"`
	// Comment is the commit message that was set when committing the image
	Comment string `json:"comment,omitempty"`
	// Created is the timestamp at which the image was created
	Created time.Time `json:"created"`
	// Container is the id of the container used to commit
	Container string `json:"container,omitempty"`
	// ContainerConfig is the configuration of the container that is committed into the image
	ContainerConfig container.Config `json:"container_config,omitempty"`
	// DockerVersion specifies the version of Docker that was used to build the image
	DockerVersion string `json:"docker_version,omitempty"`
	// Author is the name of the author that was specified when committing the image
	Author string `json:"author,omitempty"`
	// Config is the configuration of the container received from the client
	Config *container.Config `json:"config,omitempty"`
	// Architecture is the hardware that the image is built and runs on
	Architecture string `json:"architecture,omitempty"`
	// OS is the operating system used to build and run the image
	OS string `json:"os,omitempty"`
	// Size is the total size of the image including all layers it is composed of
	Size int64 `json:",omitempty"`
}

// Image stores the image configuration
type Image struct {
	V1Image
	Parent     ID        `json:"parent,omitempty"`
	RootFS     *RootFS   `json:"rootfs,omitempty"`
	History    []History `json:"history,omitempty"`
	OSVersion  string    `json:"os.version,omitempty"`
	OSFeatures []string  `json:"os.features,omitempty"`

	// rawJSON caches the immutable JSON associated with this image.
	rawJSON []byte

	// computedID is the ID computed from the hash of the image config.
	// Not to be confused with the legacy V1 ID in V1Image.
	computedID ID
}

// RawJSON returns the immutable JSON associated with the image.
func (img *Image) RawJSON() []byte {
	return img.rawJSON
}

// ID returns the image's content-addressable ID.
func (img *Image) ID() ID {
	return img.computedID
}

// ImageID stringifies ID.
func (img *Image) ImageID() string {
	return img.ID().String()
}

// RunConfig returns the image's container config.
func (img *Image) RunConfig() *container.Config {
	return img.Config
}

// MarshalJSON serializes the image to JSON. It sorts the top-level keys so
// that JSON that's been manipulated by a push/pull cycle with a legacy
// registry won't end up with a different key order.
func (img *Image) MarshalJSON() ([]byte, error) {
	type MarshalImage Image

	pass1, err := json.Marshal(MarshalImage(*img))
	if err != nil {
		return nil, err
	}

	var c map[string]*json.RawMessage
	if err := json.Unmarshal(pass1, &c); err != nil {
		return nil, err
	}
	return json.Marshal(c)
}

// History stores build commands that were used to create an image
type History struct {
	// Created is the timestamp at which the image was created
	Created time.Time `json:"created"`
	// Author is the name of the author that was specified when committing the image
	Author string `json:"author,omitempty"`
	// CreatedBy keeps the Dockerfile command used while building the image
	CreatedBy string `json:"created_by,omitempty"`
	// Comment is the commit message that was set when committing the image
	Comment string `json:"comment,omitempty"`
	// EmptyLayer is set to true if this history item did not generate a
	// layer. Otherwise, the history item is associated with the next
	// layer in the RootFS section.
	EmptyLayer bool `json:"empty_layer,omitempty"`
}

// Exporter provides interface for loading and saving images
type Exporter interface {
	Load(io.ReadCloser, io.Writer, bool) error
	// TODO: Load(net.Context, io.ReadCloser, <- chan StatusMessage) error
	Save([]string, io.Writer) error
}

// NewFromJSON creates an Image configuration from json.
func NewFromJSON(src []byte) (*Image, error) {
	img := &Image{}

	if err := json.Unmarshal(src, img); err != nil {
		return nil, err
	}
	if img.RootFS == nil {
		return nil, errors.New("invalid image JSON, no RootFS key")
	}

	img.rawJSON = src

	return img, nil
}
<|endoftext|>


<commit_before>// go-qrcode
// Copyright 2014 Tom Harwood

package main

import (
	"bytes"
	"flag"
	"fmt"
	"os"
	"strings"

	qrcode "github.com/skip2/go-qrcode"
)

func main() {
	outFile := flag.String("o", "", "out PNG file prefix, empty for stdout")
	size := flag.Int("s", 256, "image size (pixel)")
	textArt := flag.Bool("t", false, "print as text-art on stdout")
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, `qrcode -- QR Code encoder in Go
https://github.com/skip2/go-qrcode

Flags:
`)
		flag.PrintDefaults()
		fmt.Fprintf(os.Stderr, `
Usage:
  1. Arguments except for flags are joined by " " and used to generate QR code.
     Default output is STDOUT, pipe to imagemagick command "display" to display
     on any X server.

       qrcode hello word | display

  2. Save to file if "display" not available:

       qrcode "homepage: https://github.com/skip2/go-qrcode" > out.png

`)
	}
	flag.Parse()

	if *size <= 0 {
		checkError(fmt.Errorf("Error: value of -s should > 0"))
	}
	if len(flag.Args()) == 0 {
		flag.Usage()
		checkError(fmt.Errorf("Error: no content given"))
	}

	content := strings.Join(flag.Args(), " ")

	var err error
	var q *qrcode.QRCode
	q, err = qrcode.New(content, qrcode.Highest)
	checkError(err)

	if *textArt {
		art := qr2String(q, false)
		fmt.Println(art)
		return
	}

	var png []byte
	png, err = q.PNG(*size)
	checkError(err)

	if *outFile == "" {
		os.Stdout.Write(png)
	} else {
		var fh *os.File
		fh, err = os.Create(*outFile + ".png")
		checkError(err)
		defer fh.Close()
		fh.Write(png)
	}
}

func checkError(err error) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err)
		os.Exit(1)
	}
}

// qr2String produces a multi-line string that forms a QR-code image.
func qr2String(qr *qrcode.QRCode, inverseColor bool) string {
	bits := qr.Bitmap()
	var buf bytes.Buffer
	for y := range bits {
		for x := range bits[y] {
			if bits[y][x] != inverseColor {
				buf.WriteString("  ")
			} else {
				buf.WriteString("██")
			}
		}
		buf.WriteString("\n")
	}
	return buf.String()
}
<commit_msg>Extra flag -i to invert black and white (negative photo).<commit_after>// go-qrcode
// Copyright 2014 Tom Harwood

package main

import (
	"bytes"
	"flag"
	"fmt"
	"os"
	"strings"

	qrcode "github.com/skip2/go-qrcode"
)

func main() {
	outFile := flag.String("o", "", "out PNG file prefix, empty for stdout")
	size := flag.Int("s", 256, "image size (pixel)")
	textArt := flag.Bool("t", false, "print as text-art on stdout")
	negative := flag.Bool("i", false, "invert black and white")
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, `qrcode -- QR Code encoder in Go
https://github.com/skip2/go-qrcode

Flags:
`)
		flag.PrintDefaults()
		fmt.Fprintf(os.Stderr, `
Usage:
  1. Arguments except for flags are joined by " " and used to generate QR code.
     Default output is STDOUT, pipe to imagemagick command "display" to display
     on any X server.

       qrcode hello word | display

  2. Save to file if "display" not available:

       qrcode "homepage: https://github.com/skip2/go-qrcode" > out.png

`)
	}
	flag.Parse()

	if *size <= 0 {
		checkError(fmt.Errorf("Error: value of -s should > 0"))
	}
	if len(flag.Args()) == 0 {
		flag.Usage()
		checkError(fmt.Errorf("Error: no content given"))
	}

	content := strings.Join(flag.Args(), " ")

	var err error
	var q *qrcode.QRCode
	q, err = qrcode.New(content, qrcode.Highest)
	checkError(err)

	if *textArt {
		art := qr2String(q, *negative)
		fmt.Println(art)
		return
	}

	if *negative {
		q.ForegroundColor, q.BackgroundColor = q.BackgroundColor, q.ForegroundColor
	}

	var png []byte
	png, err = q.PNG(*size)
	checkError(err)

	if *outFile == "" {
		os.Stdout.Write(png)
	} else {
		var fh *os.File
		fh, err = os.Create(*outFile + ".png")
		checkError(err)
		defer fh.Close()
		fh.Write(png)
	}
}

func checkError(err error) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err)
		os.Exit(1)
	}
}

// qr2String produces a multi-line string that forms a QR-code image.
func qr2String(qr *qrcode.QRCode, inverseColor bool) string {
	bits := qr.Bitmap()
	var buf bytes.Buffer
	for y := range bits {
		for x := range bits[y] {
			if bits[y][x] != inverseColor {
				buf.WriteString("  ")
			} else {
				buf.WriteString("██")
			}
		}
		buf.WriteString("\n")
	}
	return buf.String()
}
<|endoftext|>


<commit_before>package shell

import (
	"bytes"
	"os"
	"text/template"
)

const tmpl = `#!/usr/bin/env zsh
antibody() {
	case "$1" in
	bundle)
		source <( {{ . }} $@ ) || {{ . }} $@
		;;
	*)
		{{ . }} $@
		;;
	esac
}

_antibody() {
	IFS=' ' read -A reply <<< "$(echo "bundle update list home init help")"
}
compctl -K _antibody antibody
`

// Init returns the shell that should be loaded to antibody to work correctly.
func Init() (string, error) {
	executable, err := os.Executable()
	if err != nil {
		return "", err
	}
	var template = template.Must(template.New("init").Parse(tmpl))
	var out bytes.Buffer
	err = template.Execute(&out, executable)
	return out.String(), err
}
<commit_msg>fix: better _antibody<commit_after>package shell

import (
	"bytes"
	"os"
	"text/template"
)

const tmpl = `#!/usr/bin/env zsh
antibody() {
	case "$1" in
	bundle)
		source <( {{ . }} $@ ) || {{ . }} $@
		;;
	*)
		{{ . }} $@
		;;
	esac
}

_antibody() {
	IFS=' ' read -A reply <<< "help bundle update home purge list init"
}
compctl -K _antibody antibody
`

// Init returns the shell that should be loaded to antibody to work correctly.
func Init() (string, error) {
	executable, err := os.Executable()
	if err != nil {
		return "", err
	}
	var template = template.Must(template.New("init").Parse(tmpl))
	var out bytes.Buffer
	err = template.Execute(&out, executable)
	return out.String(), err
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"go/ast"
	"go/format"
	"go/parser"
	"go/token"
	"log"
	"os"
	"path/filepath"
	"strings"
	"unicode"
	"unicode/utf8"
)

const (
	zenrpcComment       = "//zenrpc"
	zenrpcService       = "zenrpc.Service"
	contextTypeName     = "context.Context"
	generateFilePostfix = "_zenrpc.go"
)

func main() {
	var filename string
	if len(os.Args) > 1 {
		filename = os.Args[len(os.Args)-1]
	} else {
		filename = os.Getenv("GOFILE")
	}

	log.Printf("Entrypoint: %s", filename)
	structData, err := parse(filename)
	die(err)

	dir, err := filepath.Abs(filepath.Dir(filename))
	die(err)

	outputFileName := filepath.Join(dir, structData.PackageName+generateFilePostfix)
	file, err := os.Create(outputFileName)
	die(err)
	defer file.Close()

	output := new(bytes.Buffer)
	die(serviceTemplate.Execute(output, structData))

	source, err := format.Source(output.Bytes())
	die(err)

	_, err = file.Write(source)
	die(err)

	log.Printf("Generated: %s", outputFileName)
}

func die(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

// StructData represents struct info for XXX_zenrpc.go file generation.
type StructData struct {
	PackageName string
	Services    map[string]Service
}

type Service struct {
	GenDecl *ast.GenDecl
	Name    string
	Methods map[string]*Method
}

type Method struct {
	FuncDecl      *ast.FuncType
	Name          string
	LowerCaseName string
	HasContext    bool
	Args          []Arg
}

type Arg struct {
	Name        string
	Type        string
	CapitalName string
	JsonName    string
}

func parse(filename string) (StructData, error) {
	data := StructData{}
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, filename, nil, parser.ParseComments)
	if err != nil {
		return data, err
	}
	//ast.Print(fset, f) // TODO remove

	data.PackageName = f.Name.Name

	// get structs for zenrpc
	data.Services = make(map[string]Service)
	for _, decl := range f.Decls {
		gdecl, ok := decl.(*ast.GenDecl)
		if !ok || gdecl.Tok != token.TYPE {
			continue
		}

		for _, spec := range gdecl.Specs {
			spec, ok := spec.(*ast.TypeSpec)
			if !ok {
				continue
			}

			if !ast.IsExported(spec.Name.Name) {
				continue
			}

			structType, ok := spec.Type.(*ast.StructType)
			if !ok {
				continue
			}

			// check that struct is our zenrpc struct
			if hasZenrpcComment(spec) || hasZenrpcService(structType) {
				data.Services[spec.Name.Name] = Service{gdecl, spec.Name.Name, make(map[string]*Method)}
			}
		}
	}

	// get funcs for structs
	for _, decl := range f.Decls {
		fdecl, ok := decl.(*ast.FuncDecl)
		if !ok || fdecl.Recv == nil {
			continue
		}

		method := Method{
			FuncDecl:      fdecl.Type,
			Name:          fdecl.Name.Name,
			LowerCaseName: strings.ToLower(fdecl.Name.Name),
			Args:          []Arg{},
		}

		for _, field := range fdecl.Recv.List {
			// field can be pointer or not
			var ident *ast.Ident
			if starExpr, ok := field.Type.(*ast.StarExpr); ok {
				if ident, ok = starExpr.X.(*ast.Ident); !ok {
					continue
				}
			} else if ident, ok = field.Type.(*ast.Ident); !ok {
				continue
			}

			// find service in our service list
			// method can be in several services
			if _, ok := data.Services[ident.Name]; !ok {
				continue
			}

			if !ast.IsExported(fdecl.Name.Name) {
				continue
			}

			data.Services[ident.Name].Methods[fdecl.Name.Name] = &method
		}

		// parse arguments
		if fdecl.Type.Params == nil || fdecl.Type.Params.List == nil {
			continue
		}

		for _, field := range fdecl.Type.Params.List {
			if field.Names == nil {
				continue
			}

			// parse type
			typeName := ""
			switch v := field.Type.(type) {
			case *ast.StarExpr:
				// pointer
				typeName += "*" // TODO not implemented
			case *ast.SelectorExpr:
				// struct
				x, ok := v.X.(*ast.Ident)
				if ok && v.Sel != nil { // TODO check it
					typeName = x.Name + "." + v.Sel.Name
				} else {
					continue
				}
			case *ast.Ident:
				// basic types
				typeName = v.Name
			default:
				continue
			}

			if typeName == contextTypeName {
				method.HasContext = true
				continue // not add context to arg list
			}

			// parse names
			for _, name := range field.Names {
				method.Args = append(method.Args, Arg{
					Name:        name.Name,
					Type:        typeName,
					CapitalName: strings.Title(name.Name),
					JsonName:    lowerFirst(name.Name),
				})
			}
		}
	}

	return data, nil
}

func hasZenrpcComment(spec *ast.TypeSpec) bool {
	if spec.Comment != nil && len(spec.Comment.List) > 0 && spec.Comment.List[0].Text == zenrpcComment {
		return true
	}

	return false
}

func hasZenrpcService(structType *ast.StructType) bool {
	if structType.Fields.List == nil {
		return false
	}

	for _, field := range structType.Fields.List {
		selectorExpr, ok := field.Type.(*ast.SelectorExpr)
		if !ok {
			continue
		}

		x, ok := selectorExpr.X.(*ast.Ident)
		if ok && selectorExpr.Sel != nil && x.Name+"."+selectorExpr.Sel.Name == zenrpcService {
			return true
		}
	}

	return false
}

func lowerFirst(s string) string {
	if s == "" {
		return ""
	}
	r, n := utf8.DecodeRuneInString(s)
	return string(unicode.ToLower(r)) + s[n:]
}
<commit_msg>Introduce support of parsing all files associated with passed package in zenrpc util<commit_after>package main

import (
	"bytes"
	"go/ast"
	"go/format"
	"go/parser"
	"go/token"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"
	"unicode"
	"unicode/utf8"
)

const (
	zenrpcComment      = "//zenrpc"
	zenrpcService      = "zenrpc.Service"
	contextTypeName    = "context.Context"
	generateFileSuffix = "_zenrpc.go"
	testFileSuffix     = "_test.go"
)

func main() {
	var filename string
	if len(os.Args) > 1 {
		filename = os.Args[len(os.Args)-1]
	} else {
		filename = os.Getenv("GOFILE")
	}

	log.Printf("Entrypoint: %s", filename)

	structData := StructData{}
	structData.Services = make(map[string]Service)
	dir, err := parseFiles(filename, &structData)
	if err != nil {
		log.Fatal(err)
	}

	outputFileName, err := generateFile(dir, &structData)
	if err != nil {
		log.Fatal(err)
	}

	log.Printf("Generated: %s", outputFileName)
}

// StructData represents struct info for XXX_zenrpc.go file generation.
type StructData struct {
	PackageName string
	Services    map[string]Service
}

type Service struct {
	GenDecl *ast.GenDecl
	Name    string
	Methods map[string]*Method
}

type Method struct {
	FuncDecl      *ast.FuncType
	Name          string
	LowerCaseName string
	HasContext    bool
	Args          []Arg
}

type Arg struct {
	Name        string
	Type        string
	CapitalName string
	JsonName    string
}

// parseFiles parse all files associated with package from original file
func parseFiles(filename string, structData *StructData) (string, error) {
	dir, err := filepath.Abs(filepath.Dir(filename))
	if err != nil {
		return dir, err
	}

	files, err := ioutil.ReadDir(dir)
	if err != nil {
		return dir, err
	}
	for _, f := range files {
		if f.IsDir() {
			continue
		}

		if strings.HasSuffix(f.Name(), generateFileSuffix) || strings.HasSuffix(f.Name(), testFileSuffix) {
			continue
		}

		if err := parseFile(filepath.Join(dir, f.Name()), structData); err != nil {
			return dir, err
		}
	}

	return dir, nil
}

func generateFile(dir string, structData *StructData) (string, error) {
	outputFileName := filepath.Join(dir, structData.PackageName+generateFileSuffix)
	file, err := os.Create(outputFileName)
	if err != nil {
		return outputFileName, err
	}
	defer file.Close()

	output := new(bytes.Buffer)
	if err := serviceTemplate.Execute(output, structData); err != nil {
		return outputFileName, err
	}

	source, err := format.Source(output.Bytes())
	if err != nil {
		return outputFileName, err
	}

	if _, err = file.Write(source); err != nil {
		return outputFileName, err
	}

	return outputFileName, nil
}

func parseFile(filename string, data *StructData) error {
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, filename, nil, parser.ParseComments)
	if err != nil {
		return err
	}
	//ast.Print(fset, f) // TODO remove

	if len(data.PackageName) == 0 {
		data.PackageName = f.Name.Name
	} else if data.PackageName != f.Name.Name {
		return nil
	}

	// get structs for zenrpc
	for _, decl := range f.Decls {
		gdecl, ok := decl.(*ast.GenDecl)
		if !ok || gdecl.Tok != token.TYPE {
			continue
		}

		for _, spec := range gdecl.Specs {
			spec, ok := spec.(*ast.TypeSpec)
			if !ok {
				continue
			}

			if !ast.IsExported(spec.Name.Name) {
				continue
			}

			structType, ok := spec.Type.(*ast.StructType)
			if !ok {
				continue
			}

			// check that struct is our zenrpc struct
			if hasZenrpcComment(spec) || hasZenrpcService(structType) {
				data.Services[spec.Name.Name] = Service{gdecl, spec.Name.Name, make(map[string]*Method)}
			}
		}
	}

	// get funcs for structs
	for _, decl := range f.Decls {
		fdecl, ok := decl.(*ast.FuncDecl)
		if !ok || fdecl.Recv == nil {
			continue
		}

		method := Method{
			FuncDecl:      fdecl.Type,
			Name:          fdecl.Name.Name,
			LowerCaseName: strings.ToLower(fdecl.Name.Name),
			Args:          []Arg{},
		}

		for _, field := range fdecl.Recv.List {
			// field can be pointer or not
			var ident *ast.Ident
			if starExpr, ok := field.Type.(*ast.StarExpr); ok {
				if ident, ok = starExpr.X.(*ast.Ident); !ok {
					continue
				}
			} else if ident, ok = field.Type.(*ast.Ident); !ok {
				continue
			}

			// find service in our service list
			// method can be in several services
			if _, ok := data.Services[ident.Name]; !ok {
				continue
			}

			if !ast.IsExported(fdecl.Name.Name) {
				continue
			}

			data.Services[ident.Name].Methods[fdecl.Name.Name] = &method
		}

		// parse arguments
		if fdecl.Type.Params == nil || fdecl.Type.Params.List == nil {
			continue
		}

		for _, field := range fdecl.Type.Params.List {
			if field.Names == nil {
				continue
			}

			// parse type
			typeName := ""
			switch v := field.Type.(type) {
			case *ast.StarExpr:
				// pointer
				typeName += "*" // TODO not implemented
			case *ast.SelectorExpr:
				// struct
				x, ok := v.X.(*ast.Ident)
				if ok && v.Sel != nil { // TODO check it
					typeName = x.Name + "." + v.Sel.Name
				} else {
					continue
				}
			case *ast.Ident:
				// basic types
				typeName = v.Name
			default:
				continue
			}

			if typeName == contextTypeName {
				method.HasContext = true
				continue // not add context to arg list
			}

			// parse names
			for _, name := range field.Names {
				method.Args = append(method.Args, Arg{
					Name:        name.Name,
					Type:        typeName,
					CapitalName: strings.Title(name.Name),
					JsonName:    lowerFirst(name.Name),
				})
			}
		}
	}

	return nil
}

func hasZenrpcComment(spec *ast.TypeSpec) bool {
	if spec.Comment != nil && len(spec.Comment.List) > 0 && spec.Comment.List[0].Text == zenrpcComment {
		return true
	}

	return false
}

func hasZenrpcService(structType *ast.StructType) bool {
	if structType.Fields.List == nil {
		return false
	}

	for _, field := range structType.Fields.List {
		selectorExpr, ok := field.Type.(*ast.SelectorExpr)
		if !ok {
			continue
		}

		x, ok := selectorExpr.X.(*ast.Ident)
		if ok && selectorExpr.Sel != nil && x.Name+"."+selectorExpr.Sel.Name == zenrpcService {
			return true
		}
	}

	return false
}

func lowerFirst(s string) string {
	if s == "" {
		return ""
	}
	r, n := utf8.DecodeRuneInString(s)
	return string(unicode.ToLower(r)) + s[n:]
}
<|endoftext|>


<commit_before>package shellwords

import (
	"errors"
	"os"
	"regexp"
)

var (
	ParseEnv      bool = false
	ParseBacktick bool = false
)

var envRe = regexp.MustCompile(`\$({[a-zA-Z0-9_]+}|[a-zA-Z0-9_]+)`)

func isSpace(r rune) bool {
	switch r {
	case ' ', '\t', '\r', '\n':
		return true
	}
	return false
}

func replaceEnv(s string) string {
	return envRe.ReplaceAllStringFunc(s, func(s string) string {
		s = s[1:]
		if s[0] == '{' {
			s = s[1 : len(s)-1]
		}
		return os.Getenv(s)
	})
}

type Parser struct {
	ParseEnv      bool
	ParseBacktick bool
	Position      int
}

func NewParser() *Parser {
	return &Parser{ParseEnv, ParseBacktick, 0}
}

func (p *Parser) Parse(line string) ([]string, error) {
	args := []string{}
	buf := ""
	var escaped, doubleQuoted, singleQuoted, backQuote, dollarEnv bool
	backtick := ""

	pos := -1
	got := false

loop:
	for i, r := range line {
		if escaped {
			buf += string(r)
			escaped = false
			continue
		}

		if r == '\\' {
			if singleQuoted {
				buf += string(r)
			} else {
				escaped = true
			}
			continue
		}

		if isSpace(r) {
			if singleQuoted || doubleQuoted || backQuote || dollarEnv {
				buf += string(r)
				backtick += string(r)
			} else if got {
				if p.ParseEnv {
					buf = replaceEnv(buf)
				}
				args = append(args, buf)
				buf = ""
				got = false
			}
			continue
		}

		switch r {
		case '`':
			if !singleQuoted && !doubleQuoted && !dollarEnv {
				if p.ParseBacktick {
					if backQuote {
						out, err := shellRun(backtick)
						if err != nil {
							return nil, err
						}
						buf = out
					}
					backtick = ""
					backQuote = !backQuote
					continue
				}
				backtick = ""
				backQuote = !backQuote
			}
		case ')':
			if !singleQuoted && !doubleQuoted && !backQuote {
				if p.ParseBacktick {
					if dollarEnv {
						out, err := shellRun(backtick)
						if err != nil {
							return nil, err
						}
						buf = out
					}
					backtick = ""
					dollarEnv = !dollarEnv
					continue
				}
				backtick = ""
				dollarEnv = !dollarEnv
			}
		case '(':
			if !singleQuoted && !doubleQuoted && !backQuote && !dollarEnv && len(buf) > 0 && buf == "$" {
				dollarEnv = true
				continue
			}
		case '"':
			if !singleQuoted {
				doubleQuoted = !doubleQuoted
				continue
			}
		case '\'':
			if !doubleQuoted {
				singleQuoted = !singleQuoted
				continue
			}
		case ';', '&', '|', '<', '>':
			if !(escaped || singleQuoted || doubleQuoted || backQuote) {
				pos = i
				break loop
			}
		}

		got = true
		buf += string(r)
		if backQuote || dollarEnv {
			backtick += string(r)
		}
	}

	if got {
		if p.ParseEnv {
			buf = replaceEnv(buf)
		}
		args = append(args, buf)
	}

	if escaped || singleQuoted || doubleQuoted || backQuote || dollarEnv {
		return nil, errors.New("invalid command line string")
	}

	p.Position = pos

	return args, nil
}

func Parse(line string) ([]string, error) {
	return NewParser().Parse(line)
}
<commit_msg>s/dollarEnv/dollarQuote/g<commit_after>package shellwords

import (
	"errors"
	"os"
	"regexp"
)

var (
	ParseEnv      bool = false
	ParseBacktick bool = false
)

var envRe = regexp.MustCompile(`\$({[a-zA-Z0-9_]+}|[a-zA-Z0-9_]+)`)

func isSpace(r rune) bool {
	switch r {
	case ' ', '\t', '\r', '\n':
		return true
	}
	return false
}

func replaceEnv(s string) string {
	return envRe.ReplaceAllStringFunc(s, func(s string) string {
		s = s[1:]
		if s[0] == '{' {
			s = s[1 : len(s)-1]
		}
		return os.Getenv(s)
	})
}

type Parser struct {
	ParseEnv      bool
	ParseBacktick bool
	Position      int
}

func NewParser() *Parser {
	return &Parser{ParseEnv, ParseBacktick, 0}
}

func (p *Parser) Parse(line string) ([]string, error) {
	args := []string{}
	buf := ""
	var escaped, doubleQuoted, singleQuoted, backQuote, dollarQuote bool
	backtick := ""

	pos := -1
	got := false

loop:
	for i, r := range line {
		if escaped {
			buf += string(r)
			escaped = false
			continue
		}

		if r == '\\' {
			if singleQuoted {
				buf += string(r)
			} else {
				escaped = true
			}
			continue
		}

		if isSpace(r) {
			if singleQuoted || doubleQuoted || backQuote || dollarQuote {
				buf += string(r)
				backtick += string(r)
			} else if got {
				if p.ParseEnv {
					buf = replaceEnv(buf)
				}
				args = append(args, buf)
				buf = ""
				got = false
			}
			continue
		}

		switch r {
		case '`':
			if !singleQuoted && !doubleQuoted && !dollarQuote {
				if p.ParseBacktick {
					if backQuote {
						out, err := shellRun(backtick)
						if err != nil {
							return nil, err
						}
						buf = out
					}
					backtick = ""
					backQuote = !backQuote
					continue
				}
				backtick = ""
				backQuote = !backQuote
			}
		case ')':
			if !singleQuoted && !doubleQuoted && !backQuote {
				if p.ParseBacktick {
					if dollarQuote {
						out, err := shellRun(backtick)
						if err != nil {
							return nil, err
						}
						buf = out
					}
					backtick = ""
					dollarQuote = !dollarQuote
					continue
				}
				backtick = ""
				dollarQuote = !dollarQuote
			}
		case '(':
			if !singleQuoted && !doubleQuoted && !backQuote && !dollarQuote && len(buf) > 0 && buf == "$" {
				dollarQuote = true
				continue
			}
		case '"':
			if !singleQuoted {
				doubleQuoted = !doubleQuoted
				continue
			}
		case '\'':
			if !doubleQuoted {
				singleQuoted = !singleQuoted
				continue
			}
		case ';', '&', '|', '<', '>':
			if !(escaped || singleQuoted || doubleQuoted || backQuote) {
				pos = i
				break loop
			}
		}

		got = true
		buf += string(r)
		if backQuote || dollarQuote {
			backtick += string(r)
		}
	}

	if got {
		if p.ParseEnv {
			buf = replaceEnv(buf)
		}
		args = append(args, buf)
	}

	if escaped || singleQuoted || doubleQuoted || backQuote || dollarQuote {
		return nil, errors.New("invalid command line string")
	}

	p.Position = pos

	return args, nil
}

func Parse(line string) ([]string, error) {
	return NewParser().Parse(line)
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"testing"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/codecommit"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
)

func TestAccAWSCodeCommitRepository_basic(t *testing.T) {
	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckCodeCommitRepositoryDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccCodeCommitRepository_basic,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckCodeCommitRepositoryExists("aws_codecommit_repository.test"),
				),
			},
		},
	})
}

func TestAccAWSCodeCommitRepository_withChanges(t *testing.T) {
	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckCodeCommitRepositoryDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccCodeCommitRepository_basic,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckCodeCommitRepositoryExists("aws_codecommit_repository.test"),
					resource.TestCheckResourceAttr(
						"aws_codecommit_repository.test", "description", "This is a test description"),
				),
			},
			resource.TestStep{
				Config: testAccCodeCommitRepository_withChanges,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckCodeCommitRepositoryExists("aws_codecommit_repository.test"),
					resource.TestCheckResourceAttr(
						"aws_codecommit_repository.test", "description", "This is a test description - with changes"),
				),
			},
		},
	})
}

func testAccCheckCodeCommitRepositoryExists(name string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[name]
		if !ok {
			return fmt.Errorf("Not found: %s", name)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("No ID is set")
		}

		codecommitconn := testAccProvider.Meta().(*AWSClient).codecommitconn
		out, err := codecommitconn.GetRepository(&codecommit.GetRepositoryInput{
			RepositoryName: aws.String(rs.Primary.ID),
		})

		if err != nil {
			return err
		}

		if out.RepositoryMetadata.Arn == nil {
			return fmt.Errorf("No CodeCommit Repository Vault Found")
		}

		if *out.RepositoryMetadata.RepositoryName != rs.Primary.ID {
			return fmt.Errorf("CodeCommit Repository Mismatch - existing: %q, state: %q",
				*out.RepositoryMetadata.RepositoryName, rs.Primary.ID)
		}

		return nil
	}
}

func testAccCheckCodeCommitRepositoryDestroy(s *terraform.State) error {
	conn := testAccProvider.Meta().(*AWSClient).codecommitconn

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "aws_codecommit_repository" {
			continue
		}

		_, err := conn.GetRepository(&codecommit.GetRepositoryInput{
			RepositoryName: aws.String(rs.Primary.ID),
		})

		if ae, ok := err.(awserr.Error); ok && ae.Code() == "RepositoryDoesNotExistException" {
			continue
		}
		if err == nil {
			return fmt.Errorf("Repository still exists: %s", rs.Primary.ID)
		}
		return err
	}

	return nil
}

const testAccCodeCommitRepository_basic = `
provider "aws" {
  region = "us-east-1"
}
resource "aws_codecommit_repository" "test" {
  repository_name = "my_test_repository"
  description = "This is a test description"
}
`

const testAccCodeCommitRepository_withChanges = `
provider "aws" {
  region = "us-east-1"
}
resource "aws_codecommit_repository" "test" {
  repository_name = "my_test_repository"
  description = "This is a test description - with changes"
}
`
<commit_msg>provider/aws: Add tests for default_branch in new codecommit repos<commit_after>package aws

import (
	"fmt"
	"testing"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/codecommit"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
)

func TestAccAWSCodeCommitRepository_basic(t *testing.T) {
	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckCodeCommitRepositoryDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccCodeCommitRepository_basic,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckCodeCommitRepositoryExists("aws_codecommit_repository.test"),
				),
			},
		},
	})
}

func TestAccAWSCodeCommitRepository_withChanges(t *testing.T) {
	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckCodeCommitRepositoryDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccCodeCommitRepository_basic,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckCodeCommitRepositoryExists("aws_codecommit_repository.test"),
					resource.TestCheckResourceAttr(
						"aws_codecommit_repository.test", "description", "This is a test description"),
				),
			},
			resource.TestStep{
				Config: testAccCodeCommitRepository_withChanges,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckCodeCommitRepositoryExists("aws_codecommit_repository.test"),
					resource.TestCheckResourceAttr(
						"aws_codecommit_repository.test", "description", "This is a test description - with changes"),
				),
			},
		},
	})
}

func TestAccAWSCodeCommitRepository_create_default_branch(t *testing.T) {
	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckCodeCommitRepositoryDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccCodeCommitRepository_with_default_branch,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckCodeCommitRepositoryExists("aws_codecommit_repository.test"),
					resource.TestCheckResourceAttr(
						"aws_codecommit_repository.test", "default_branch", "master"),
				),
			},
		},
	})
}

func TestAccAWSCodeCommitRepository_create_and_update_default_branch(t *testing.T) {
	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckCodeCommitRepositoryDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccCodeCommitRepository_basic,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckCodeCommitRepositoryExists("aws_codecommit_repository.test"),
					resource.TestCheckResourceAttr(
						"aws_codecommit_repository.test", "default_branch", ""),
				),
			},
			resource.TestStep{
				Config: testAccCodeCommitRepository_with_default_branch,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckCodeCommitRepositoryExists("aws_codecommit_repository.test"),
					resource.TestCheckResourceAttr(
						"aws_codecommit_repository.test", "default_branch", "master"),
				),
			},
		},
	})
}

func testAccCheckCodeCommitRepositoryExists(name string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[name]
		if !ok {
			return fmt.Errorf("Not found: %s", name)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("No ID is set")
		}

		codecommitconn := testAccProvider.Meta().(*AWSClient).codecommitconn
		out, err := codecommitconn.GetRepository(&codecommit.GetRepositoryInput{
			RepositoryName: aws.String(rs.Primary.ID),
		})

		if err != nil {
			return err
		}

		if out.RepositoryMetadata.Arn == nil {
			return fmt.Errorf("No CodeCommit Repository Vault Found")
		}

		if *out.RepositoryMetadata.RepositoryName != rs.Primary.ID {
			return fmt.Errorf("CodeCommit Repository Mismatch - existing: %q, state: %q",
				*out.RepositoryMetadata.RepositoryName, rs.Primary.ID)
		}

		return nil
	}
}

func testAccCheckCodeCommitRepositoryDestroy(s *terraform.State) error {
	conn := testAccProvider.Meta().(*AWSClient).codecommitconn

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "aws_codecommit_repository" {
			continue
		}

		_, err := conn.GetRepository(&codecommit.GetRepositoryInput{
			RepositoryName: aws.String(rs.Primary.ID),
		})

		if ae, ok := err.(awserr.Error); ok && ae.Code() == "RepositoryDoesNotExistException" {
			continue
		}
		if err == nil {
			return fmt.Errorf("Repository still exists: %s", rs.Primary.ID)
		}
		return err
	}

	return nil
}

const testAccCodeCommitRepository_basic = `
provider "aws" {
  region = "us-east-1"
}
resource "aws_codecommit_repository" "test" {
  repository_name = "my_test_repository"
  description = "This is a test description"
}
`

const testAccCodeCommitRepository_withChanges = `
provider "aws" {
  region = "us-east-1"
}
resource "aws_codecommit_repository" "test" {
  repository_name = "my_test_repository"
  description = "This is a test description - with changes"
}
`

const testAccCodeCommitRepository_with_default_branch = `
provider "aws" {
  region = "us-east-1"
}
resource "aws_codecommit_repository" "test" {
  repository_name = "my_test_repository"
  description = "This is a test description"
  default_branch = "master"
}
`
<|endoftext|>