<commit_before>package lmdb

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"syscall"
	"testing"
)

func TestEnv_Path_notOpen(t *testing.T) {
	env, err := NewEnv()
	if err != nil {
		t.Fatalf("create: %v", err)
	}
	defer env.Close()

	// before Open the Path method returns "" and a non-nil error.
	path, err := env.Path()
	if err == nil {
		t.Errorf("no error returned before Open")
	}
	if path != "" {
		t.Errorf("non-zero path returned before Open")
	}
}

func TestEnv_Path(t *testing.T) {
	env, err := NewEnv()
	if err != nil {
		t.Fatalf("create: %v", err)
	}

	// open an environment
	dir, err := ioutil.TempDir("", "mdb_test")
	if err != nil {
		t.Fatalf("tempdir: %v", err)
	}
	defer os.RemoveAll(dir)

	err = env.Open(dir, 0, 0644)
	defer env.Close()
	if err != nil {
		t.Errorf("open: %v", err)
	}
	path, err := env.Path()
	if err != nil {
		t.Errorf("path: %v", err)
	}
	if path != dir {
		t.Errorf("path: %q (!= %q)", path, dir)
	}
}

func TestEnv_Open_notExist(t *testing.T) {
	env, err := NewEnv()
	if err != nil {
		t.Fatalf("create: %s", err)
	}
	defer env.Close()

	// ensure that opening a non-existent path fails.
	err = env.Open("/path/does/not/exist/aoeu", 0, 0664)
	if !IsNotExist(err) {
		t.Errorf("open: %v", err)
	}
}

func TestEnv_Open(t *testing.T) {
	env, err := NewEnv()
	if err != nil {
		t.Error(err)
		return
	}
	defer func() {
		err := env.Close()
		if err != nil {
			t.Error(err)
		}
	}()

	// open an environment at a temporary path.
	path, err := ioutil.TempDir("/tmp", "mdb_test")
	if err != nil {
		t.Fatalf("tempdir: %v", err)
	}
	defer os.RemoveAll(path)
	err = env.Open(path, 0, 0664)
	if err != nil {
		t.Errorf("open: %s", err)
	}
}

func TestEnv_Flags(t *testing.T) {
	env := setup(t)
	defer clean(env, t)

	flags, err := env.Flags()
	if err != nil {
		t.Error(err)
		return
	}

	if flags&NoTLS == 0 {
		t.Errorf("NoTLS is not set")
	}
	if flags&NoSync != 0 {
		t.Errorf("NoSync is set")
	}

	err = env.SetFlags(NoSync)
	if err != nil {
		t.Error(err)
	}

	flags, err = env.Flags()
	if err != nil {
		t.Error(err)
	}
	if flags&NoSync == 0 {
		t.Error("NoSync is not set")
	}

	err = env.UnsetFlags(NoSync)
	if err != nil {
		t.Error(err)
	}

	flags, err = env.Flags()
	if err != nil {
		t.Error(err)
	}
	if flags&NoSync != 0 {
		t.Error("NoSync is set")
	}
}

func TestEnv_SetMaxReader(t *testing.T) {
	dir, err := ioutil.TempDir("", "test-env-setmaxreaders-")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(dir)

	env, err := NewEnv()
	if err != nil {
		t.Error(err)
	}

	maxreaders := 5
	err = env.SetMaxReaders(maxreaders)
	if err != nil {
		t.Error(err)
	}
	_maxreaders, err := env.MaxReaders()
	if err != nil {
		t.Error(err)
	}
	if _maxreaders != maxreaders {
		t.Errorf("unexpected MaxReaders: %v (!= %v)", _maxreaders, maxreaders)
	}

	err = env.Open(dir, 0, 0644)
	defer env.Close()
	if err != nil {
		env.Close()
		t.Error(err)
	}

	err = env.SetMaxReaders(126)
	if !IsErrnoSys(err, syscall.EINVAL) {
		t.Errorf("unexpected error: %v (!= %v)", err, Invalid)
	}
	_maxreaders, err = env.MaxReaders()
	if err != nil {
		t.Error(err)
	}
	if _maxreaders != maxreaders {
		t.Errorf("unexpected MaxReaders: %v (!= %v)", _maxreaders, maxreaders)
	}
}

func TestEnv_SetMapSize(t *testing.T) {
	env := setup(t)
	defer clean(env, t)

	const minsize = 100 << 20 // 100MB
	err := env.SetMapSize(minsize)
	if err != nil {
		t.Error(err)
	}

	err = env.Update(func(txn *Txn) (err error) {
		return nil
	})
	if err != nil {
		t.Error(err)
	}

	info, err := env.Info()
	if err != nil {
		t.Error(err)
	} else if info.MapSize < minsize {
		t.Errorf("unexpected mapsize: %v (< %v)", info.MapSize, minsize)
	}
}

func TestEnv_ReaderCheck(t *testing.T) {
	env := setup(t)
	defer clean(env, t)

	numDead, err := env.ReaderCheck()
	if err != nil {
		t.Error(err)
	}
	if numDead != 0 {
		t.Errorf("unexpected dead readers: %v (!= %v)", numDead, 0)
	}
}

func TestEnv_Copy(t *testing.T) {
	testEnv_Copy(t, 0, false)
}

func TestEnv_CopyFlags(t *testing.T) {
	testEnv_Copy(t, CopyCompact, true)
}

func TestEnv_CopyFlags_zero(t *testing.T) {
	testEnv_Copy(t, 0, true)
}

func testEnv_Copy(t *testing.T, flags uint, useflags bool) {
	dircp, err := ioutil.TempDir("", "test-env-copy-")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(dircp)

	env := setup(t)
	defer clean(env, t)

	item := struct{ k, v []byte }{
		[]byte("k0"),
		[]byte("v0"),
	}

	err = env.Update(func(txn *Txn) (err error) {
		db, err := txn.OpenRoot(0)
		if err != nil {
			return err
		}
		return txn.Put(db, item.k, item.v, 0)
	})
	if err != nil {
		t.Error(err)
	}

	if useflags {
		err = env.CopyFlag(dircp, flags)
	} else {
		err = env.Copy(dircp)
	}
	if err != nil {
		t.Error(err)
	}

	envcp, err := NewEnv()
	if err != nil {
		t.Error(err)
	}
	err = envcp.Open(dircp, 0, 0644)
	defer envcp.Close()
	if err != nil {
		t.Error(err)
		return
	}

	err = envcp.View(func(txn *Txn) (err error) {
		db, err := txn.OpenRoot(0)
		if err != nil {
			return err
		}
		v, err := txn.Get(db, item.k)
		if err != nil {
			return err
		}
		if !bytes.Equal(v, item.v) {
			return fmt.Errorf("unexpected value: %q (!= %q)", v, "v0")
		}
		return nil
	})
	if err != nil {
		t.Error(err)
	}
}

func setup(t T) *Env {
	env, err := NewEnv()
	if err != nil {
		t.Fatalf("env: %s", err)
	}
	path, err := ioutil.TempDir("/tmp", "mdb_test")
	if err != nil {
		t.Fatalf("tempdir: %v", err)
	}
	err = os.MkdirAll(path, 0770)
	if err != nil {
		t.Fatalf("mkdir: %s", path)
	}
	err = env.SetMaxDBs(64 << 10)
	if err != nil {
		t.Fatalf("setmaxdbs: %v", err)
	}
	err = env.Open(path, 0, 0664)
	if err != nil {
		t.Fatalf("open: %s", err)
	}

	return env
}

type T interface {
	Errorf(format string, vals ...interface{})
	Fatalf(format string, vals ...interface{})
}

func clean(env *Env, t T) {
	path, err := env.Path()
	if err != nil {
		t.Errorf("path: %v", err)
	}
	err = env.Close()
	if err != nil {
		t.Errorf("close: %s", err)
	}
	if path != "" {
		err = os.RemoveAll(path)
		if err != nil {
			t.Errorf("remove: %v", err)
		}
	}
}

func TestEnvCopy(t *testing.T) {
	env := setup(t)
	defer clean(env, t)
}

func TestEnv_MaxKeySize(t *testing.T) {
	env := setup(t)
	defer clean(env, t)

	n := env.MaxKeySize()
	if n <= 0 {
		t.Errorf("invaild maxkeysize: %d", n)
	}
}

func TestEnv_MaxKeySize_nil(t *testing.T) {
	var env *Env
	n := env.MaxKeySize()
	if n <= 0 {
		t.Errorf("invaild maxkeysize: %d", n)
	}
	t.Logf("mdb_env_get_maxkeysize: %d", n)
}
<commit_msg>test Env.Sync<commit_after>package lmdb

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"syscall"
	"testing"
)

func TestEnv_Path_notOpen(t *testing.T) {
	env, err := NewEnv()
	if err != nil {
		t.Fatalf("create: %v", err)
	}
	defer env.Close()

	// before Open the Path method returns "" and a non-nil error.
	path, err := env.Path()
	if err == nil {
		t.Errorf("no error returned before Open")
	}
	if path != "" {
		t.Errorf("non-zero path returned before Open")
	}
}

func TestEnv_Path(t *testing.T) {
	env, err := NewEnv()
	if err != nil {
		t.Fatalf("create: %v", err)
	}

	// open an environment
	dir, err := ioutil.TempDir("", "mdb_test")
	if err != nil {
		t.Fatalf("tempdir: %v", err)
	}
	defer os.RemoveAll(dir)

	err = env.Open(dir, 0, 0644)
	defer env.Close()
	if err != nil {
		t.Errorf("open: %v", err)
	}
	path, err := env.Path()
	if err != nil {
		t.Errorf("path: %v", err)
	}
	if path != dir {
		t.Errorf("path: %q (!= %q)", path, dir)
	}
}

func TestEnv_Open_notExist(t *testing.T) {
	env, err := NewEnv()
	if err != nil {
		t.Fatalf("create: %s", err)
	}
	defer env.Close()

	// ensure that opening a non-existent path fails.
	err = env.Open("/path/does/not/exist/aoeu", 0, 0664)
	if !IsNotExist(err) {
		t.Errorf("open: %v", err)
	}
}

func TestEnv_Open(t *testing.T) {
	env, err := NewEnv()
	if err != nil {
		t.Error(err)
		return
	}
	defer func() {
		err := env.Close()
		if err != nil {
			t.Error(err)
		}
	}()

	// open an environment at a temporary path.
	path, err := ioutil.TempDir("/tmp", "mdb_test")
	if err != nil {
		t.Fatalf("tempdir: %v", err)
	}
	defer os.RemoveAll(path)
	err = env.Open(path, 0, 0664)
	if err != nil {
		t.Errorf("open: %s", err)
	}
}

func TestEnv_Flags(t *testing.T) {
	env := setup(t)
	defer clean(env, t)

	flags, err := env.Flags()
	if err != nil {
		t.Error(err)
		return
	}

	if flags&NoTLS == 0 {
		t.Errorf("NoTLS is not set")
	}
	if flags&NoSync != 0 {
		t.Errorf("NoSync is set")
	}

	err = env.SetFlags(NoSync)
	if err != nil {
		t.Error(err)
	}

	flags, err = env.Flags()
	if err != nil {
		t.Error(err)
	}
	if flags&NoSync == 0 {
		t.Error("NoSync is not set")
	}

	err = env.UnsetFlags(NoSync)
	if err != nil {
		t.Error(err)
	}

	flags, err = env.Flags()
	if err != nil {
		t.Error(err)
	}
	if flags&NoSync != 0 {
		t.Error("NoSync is set")
	}
}

func TestEnv_SetMaxReader(t *testing.T) {
	dir, err := ioutil.TempDir("", "test-env-setmaxreaders-")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(dir)

	env, err := NewEnv()
	if err != nil {
		t.Error(err)
	}

	maxreaders := 5
	err = env.SetMaxReaders(maxreaders)
	if err != nil {
		t.Error(err)
	}
	_maxreaders, err := env.MaxReaders()
	if err != nil {
		t.Error(err)
	}
	if _maxreaders != maxreaders {
		t.Errorf("unexpected MaxReaders: %v (!= %v)", _maxreaders, maxreaders)
	}

	err = env.Open(dir, 0, 0644)
	defer env.Close()
	if err != nil {
		env.Close()
		t.Error(err)
	}

	err = env.SetMaxReaders(126)
	if !IsErrnoSys(err, syscall.EINVAL) {
		t.Errorf("unexpected error: %v (!= %v)", err, Invalid)
	}
	_maxreaders, err = env.MaxReaders()
	if err != nil {
		t.Error(err)
	}
	if _maxreaders != maxreaders {
		t.Errorf("unexpected MaxReaders: %v (!= %v)", _maxreaders, maxreaders)
	}
}

func TestEnv_SetMapSize(t *testing.T) {
	env := setup(t)
	defer clean(env, t)

	const minsize = 100 << 20 // 100MB
	err := env.SetMapSize(minsize)
	if err != nil {
		t.Error(err)
	}

	err = env.Update(func(txn *Txn) (err error) {
		return nil
	})
	if err != nil {
		t.Error(err)
	}

	info, err := env.Info()
	if err != nil {
		t.Error(err)
	} else if info.MapSize < minsize {
		t.Errorf("unexpected mapsize: %v (< %v)", info.MapSize, minsize)
	}
}

func TestEnv_ReaderCheck(t *testing.T) {
	env := setup(t)
	defer clean(env, t)

	numDead, err := env.ReaderCheck()
	if err != nil {
		t.Error(err)
	}
	if numDead != 0 {
		t.Errorf("unexpected dead readers: %v (!= %v)", numDead, 0)
	}
}

func TestEnv_Copy(t *testing.T) {
	testEnv_Copy(t, 0, false)
}

func TestEnv_CopyFlags(t *testing.T) {
	testEnv_Copy(t, CopyCompact, true)
}

func TestEnv_CopyFlags_zero(t *testing.T) {
	testEnv_Copy(t, 0, true)
}

func testEnv_Copy(t *testing.T, flags uint, useflags bool) {
	dircp, err := ioutil.TempDir("", "test-env-copy-")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(dircp)

	env := setup(t)
	defer clean(env, t)

	item := struct{ k, v []byte }{
		[]byte("k0"),
		[]byte("v0"),
	}

	err = env.Update(func(txn *Txn) (err error) {
		db, err := txn.OpenRoot(0)
		if err != nil {
			return err
		}
		return txn.Put(db, item.k, item.v, 0)
	})
	if err != nil {
		t.Error(err)
	}

	if useflags {
		err = env.CopyFlag(dircp, flags)
	} else {
		err = env.Copy(dircp)
	}
	if err != nil {
		t.Error(err)
	}

	envcp, err := NewEnv()
	if err != nil {
		t.Error(err)
	}
	err = envcp.Open(dircp, 0, 0644)
	defer envcp.Close()
	if err != nil {
		t.Error(err)
		return
	}

	err = envcp.View(func(txn *Txn) (err error) {
		db, err := txn.OpenRoot(0)
		if err != nil {
			return err
		}
		v, err := txn.Get(db, item.k)
		if err != nil {
			return err
		}
		if !bytes.Equal(v, item.v) {
			return fmt.Errorf("unexpected value: %q (!= %q)", v, "v0")
		}
		return nil
	})
	if err != nil {
		t.Error(err)
	}
}

func TestEnv_Sync(t *testing.T) {
	env := setupFlags(t, NoSync)
	defer clean(env, t)

	item := struct{ k, v []byte }{[]byte("k0"), []byte("v0")}

	err := env.Update(func(txn *Txn) (err error) {
		db, err := txn.OpenRoot(0)
		if err != nil {
			return err
		}
		return txn.Put(db, item.k, item.v, 0)
	})
	if err != nil {
		t.Error(err)
	}

	err = env.Sync(true)
	if err != nil {
		t.Error(err)
	}
}

func setup(t T) *Env {
	return setupFlags(t, 0)
}

func setupFlags(t T, flags uint) *Env {
	env, err := NewEnv()
	if err != nil {
		t.Fatalf("env: %s", err)
	}
	path, err := ioutil.TempDir("/tmp", "mdb_test")
	if err != nil {
		t.Fatalf("tempdir: %v", err)
	}
	err = os.MkdirAll(path, 0770)
	if err != nil {
		t.Fatalf("mkdir: %s", path)
	}
	err = env.SetMaxDBs(64 << 10)
	if err != nil {
		t.Fatalf("setmaxdbs: %v", err)
	}
	err = env.Open(path, flags, 0664)
	if err != nil {
		t.Fatalf("open: %s", err)
	}

	return env
}

type T interface {
	Errorf(format string, vals ...interface{})
	Fatalf(format string, vals ...interface{})
}

func clean(env *Env, t T) {
	path, err := env.Path()
	if err != nil {
		t.Errorf("path: %v", err)
	}
	err = env.Close()
	if err != nil {
		t.Errorf("close: %s", err)
	}
	if path != "" {
		err = os.RemoveAll(path)
		if err != nil {
			t.Errorf("remove: %v", err)
		}
	}
}

func TestEnvCopy(t *testing.T) {
	env := setup(t)
	defer clean(env, t)
}

func TestEnv_MaxKeySize(t *testing.T) {
	env := setup(t)
	defer clean(env, t)

	n := env.MaxKeySize()
	if n <= 0 {
		t.Errorf("invaild maxkeysize: %d", n)
	}
}

func TestEnv_MaxKeySize_nil(t *testing.T) {
	var env *Env
	n := env.MaxKeySize()
	if n <= 0 {
		t.Errorf("invaild maxkeysize: %d", n)
	}
	t.Logf("mdb_env_get_maxkeysize: %d", n)
}
<|endoftext|>


<commit_before>package swaggman

import (
	"encoding/json"
	"io/ioutil"
	"regexp"
	"strings"

	"github.com/grokify/swaggman/postman2"
	"github.com/grokify/swaggman/postman2/simple"
	"github.com/grokify/swaggman/swagger2"
)

type Configuration struct {
	PostmanURLHostname string            `json:"postmanURLHostname,omitempty"`
	PostmanHeaders     []postman2.Header `json:"postmanHeaders,omitempty"`
}

type Converter struct {
	Configuration Configuration
	Swagger       swagger2.Specification
}

func NewConverter(cfg Configuration) Converter {
	return Converter{Configuration: cfg}
}

func (conv *Converter) MergeConvert(swaggerFilepath string, pmanBaseFilepath string, pmanSpecFilepath string) error {
	swag, err := swagger2.ReadSwagger2Spec(swaggerFilepath)
	if err != nil {
		return err
	}

	pman, err := simple.ReadCanonicalCollection(pmanBaseFilepath)
	if err != nil {
		return err
	}

	pm := Merge(conv.Configuration, pman, swag)

	bytes, err := json.MarshalIndent(pm, "", "  ")
	if err != nil {
		return err
	}
	return ioutil.WriteFile(pmanSpecFilepath, bytes, 0644)
}

func (conv *Converter) Convert(swaggerFilepath string, pmanSpecFilepath string) error {
	swag, err := swagger2.ReadSwagger2Spec(swaggerFilepath)
	if err != nil {
		return err
	}
	pm := Convert(conv.Configuration, swag)

	bytes, err := json.MarshalIndent(pm, "", "  ")
	if err != nil {
		return err
	}
	return ioutil.WriteFile(pmanSpecFilepath, bytes, 0644)
}

func Convert(cfg Configuration, swag swagger2.Specification) postman2.Collection {
	return Merge(cfg, postman2.Collection{}, swag)
}

func Merge(cfg Configuration, pman postman2.Collection, swag swagger2.Specification) postman2.Collection {
	if len(pman.Info.Name) == 0 {
		pman.Info.Name = strings.TrimSpace(swag.Info.Title)
	}
	if len(pman.Info.Description) == 0 {
		pman.Info.Description = strings.TrimSpace(swag.Info.Description)
	}
	if len(pman.Info.Schema) == 0 {
		pman.Info.Schema = "https://schema.getpostman.com/json/collection/v2.0.0/collection.json"
	}

	for url, path := range swag.Paths {
		if url != "/v1.0/account/{accountId}/extension" {
			//continue
		}

		if len(path.Get.Tags) > 0 {
			if len(strings.TrimSpace(path.Get.Tags[0])) > 0 {
				pmItem := Swagger2PathToPostman2ApiItem(cfg, swag, url, "GET", path.Get)
				pmFolderName := strings.TrimSpace(path.Get.Tags[0])
				pmFolder := pman.GetOrNewFolder(pmFolderName)
				pmFolder.Item = append(pmFolder.Item, pmItem)
				pman.SetFolder(pmFolder)
			}
		}
		if len(path.Post.Tags) > 0 {
			if len(strings.TrimSpace(path.Post.Tags[0])) > 0 {
				pmItem := Swagger2PathToPostman2ApiItem(cfg, swag, url, "POST", path.Post)
				pmFolderName := strings.TrimSpace(path.Post.Tags[0])
				pmFolder := pman.GetOrNewFolder(pmFolderName)
				pmFolder.Item = append(pmFolder.Item, pmItem)
				pman.SetFolder(pmFolder)
			}
		}
		if len(path.Put.Tags) > 0 {
			if len(strings.TrimSpace(path.Put.Tags[0])) > 0 {
				pmItem := Swagger2PathToPostman2ApiItem(cfg, swag, url, "PUT", path.Put)
				pmFolderName := strings.TrimSpace(path.Put.Tags[0])
				pmFolder := pman.GetOrNewFolder(pmFolderName)
				pmFolder.Item = append(pmFolder.Item, pmItem)
				pman.SetFolder(pmFolder)
			}
		}
		if len(path.Delete.Tags) > 0 {
			if len(strings.TrimSpace(path.Delete.Tags[0])) > 0 {
				pmItem := Swagger2PathToPostman2ApiItem(cfg, swag, url, "DELETE", path.Delete)
				pmFolderName := strings.TrimSpace(path.Delete.Tags[0])
				pmFolder := pman.GetOrNewFolder(pmFolderName)
				pmFolder.Item = append(pmFolder.Item, pmItem)
				pman.SetFolder(pmFolder)
			}
		}
	}

	return pman
}

func Swagger2PathToPostman2ApiItem(cfg Configuration, swag swagger2.Specification, url string, method string, endpoint swagger2.Endpoint) postman2.ApiItem {
	item := postman2.ApiItem{}

	item.Name = endpoint.Summary

	item.Request = postman2.Request{
		Method: strings.ToUpper(method)}

	item.Request.URL = BuildPostmanURL(cfg, swag, url, endpoint)

	headers := []postman2.Header{}

	if len(endpoint.Consumes) > 0 {
		if len(strings.TrimSpace(endpoint.Consumes[0])) > 0 {
			headers = append(headers, postman2.Header{
				Key:   "Content-Type",
				Value: strings.TrimSpace(endpoint.Consumes[0])})
		}
	}
	if len(endpoint.Produces) > 0 {
		if len(strings.TrimSpace(endpoint.Produces[0])) > 0 {
			headers = append(headers, postman2.Header{
				Key:   "Accept",
				Value: strings.TrimSpace(endpoint.Consumes[0])})
		}
	}
	for _, header := range cfg.PostmanHeaders {
		headers = append(headers, header)
	}

	item.Request.Header = headers

	return item
}

func BuildPostmanURL(cfg Configuration, swag swagger2.Specification, swaggerUrl string, endpoint swagger2.Endpoint) postman2.URL {
	URLParts := []string{}

	// Set URL path parts
	if len(strings.TrimSpace(cfg.PostmanURLHostname)) > 0 {
		URLParts = append(URLParts, strings.TrimSpace(cfg.PostmanURLHostname))
	} else if len(strings.TrimSpace(swag.Host)) > 0 {
		URLParts = append(URLParts, strings.TrimSpace(swag.Host))
	}

	if len(strings.TrimSpace(swag.BasePath)) > 0 {
		URLParts = append(URLParts, strings.TrimSpace(swag.BasePath))
	}
	if len(strings.TrimSpace(swaggerUrl)) > 0 {
		URLParts = append(URLParts, strings.TrimSpace(swaggerUrl))
	}

	// Create URL
	rawPostmanUrl := strings.TrimSpace(strings.Join(URLParts, "/"))
	rx1 := regexp.MustCompile(`/+`)
	rawPostmanUrl = rx1.ReplaceAllString(rawPostmanUrl, "/")
	rx2 := regexp.MustCompile(`^/+`)
	rawPostmanUrl = rx2.ReplaceAllString(rawPostmanUrl, "")

	// Add URL Scheme
	if len(swag.Schemes) > 0 {
		for _, scheme := range swag.Schemes {
			if len(strings.TrimSpace(scheme)) > 0 {
				rawPostmanUrl = strings.Join([]string{scheme, rawPostmanUrl}, "://")
				break
			}
		}
	}

	rx3 := regexp.MustCompile(`(^|[^\{])\{([^\/\{\}]+)\}([^\}]|$)`)
	rawPostmanUrl = rx3.ReplaceAllString(rawPostmanUrl, "$1:$2$3")

	postmanUrl := postman2.NewURL(rawPostmanUrl)

	// Set Default URL Path Parameters
	rx4 := regexp.MustCompile(`^\s*(:(.+))\s*$`)

	for _, part := range postmanUrl.Path {
		rs4 := rx4.FindAllStringSubmatch(part, -1)
		if len(rs4) > 0 {
			baseVariable := rs4[0][2]
			//defaultValue := ""
			var defaultValue interface{}
			for _, parameter := range endpoint.Parameters {
				if parameter.Name == baseVariable {
					defaultValue = parameter.Default
					/*
						if len(strings.TrimSpace(parameter.Default)) > 0 {
							defaultValue = strings.TrimSpace(parameter.Default)
						}
					*/
					break
				}
			}
			postmanUrl.AddVariable(baseVariable, defaultValue)
		}
	}

	return postmanUrl
}
<commit_msg>convert_swagger2_to_postman2: simplify some code<commit_after>package swaggman

import (
	"encoding/json"
	"io/ioutil"
	"regexp"
	"strings"

	"github.com/grokify/swaggman/postman2"
	"github.com/grokify/swaggman/postman2/simple"
	"github.com/grokify/swaggman/swagger2"
)

type Configuration struct {
	PostmanURLHostname string            `json:"postmanURLHostname,omitempty"`
	PostmanHeaders     []postman2.Header `json:"postmanHeaders,omitempty"`
}

type Converter struct {
	Configuration Configuration
	Swagger       swagger2.Specification
}

func NewConverter(cfg Configuration) Converter {
	return Converter{Configuration: cfg}
}

func (conv *Converter) MergeConvert(swaggerFilepath string, pmanBaseFilepath string, pmanSpecFilepath string) error {
	swag, err := swagger2.ReadSwagger2Spec(swaggerFilepath)
	if err != nil {
		return err
	}

	pman, err := simple.ReadCanonicalCollection(pmanBaseFilepath)
	if err != nil {
		return err
	}

	pm := Merge(conv.Configuration, pman, swag)

	bytes, err := json.MarshalIndent(pm, "", "  ")
	if err != nil {
		return err
	}
	return ioutil.WriteFile(pmanSpecFilepath, bytes, 0644)
}

func (conv *Converter) Convert(swaggerFilepath string, pmanSpecFilepath string) error {
	swag, err := swagger2.ReadSwagger2Spec(swaggerFilepath)
	if err != nil {
		return err
	}
	pm := Convert(conv.Configuration, swag)

	bytes, err := json.MarshalIndent(pm, "", "  ")
	if err != nil {
		return err
	}
	return ioutil.WriteFile(pmanSpecFilepath, bytes, 0644)
}

func Convert(cfg Configuration, swag swagger2.Specification) postman2.Collection {
	return Merge(cfg, postman2.Collection{}, swag)
}

func Merge(cfg Configuration, pman postman2.Collection, swag swagger2.Specification) postman2.Collection {
	if len(pman.Info.Name) == 0 {
		pman.Info.Name = strings.TrimSpace(swag.Info.Title)
	}
	if len(pman.Info.Description) == 0 {
		pman.Info.Description = strings.TrimSpace(swag.Info.Description)
	}
	if len(pman.Info.Schema) == 0 {
		pman.Info.Schema = "https://schema.getpostman.com/json/collection/v2.0.0/collection.json"
	}

	for url, path := range swag.Paths {
		if url != "/v1.0/account/{accountId}/extension" {
			//continue
		}

		if len(path.Get.Tags) > 0 {
			if len(strings.TrimSpace(path.Get.Tags[0])) > 0 {
				pmItem := Swagger2PathToPostman2ApiItem(cfg, swag, url, "GET", path.Get)
				pmFolderName := strings.TrimSpace(path.Get.Tags[0])
				pmFolder := pman.GetOrNewFolder(pmFolderName)
				pmFolder.Item = append(pmFolder.Item, pmItem)
				pman.SetFolder(pmFolder)
			}
		}
		if len(path.Post.Tags) > 0 {
			if len(strings.TrimSpace(path.Post.Tags[0])) > 0 {
				pmItem := Swagger2PathToPostman2ApiItem(cfg, swag, url, "POST", path.Post)
				pmFolderName := strings.TrimSpace(path.Post.Tags[0])
				pmFolder := pman.GetOrNewFolder(pmFolderName)
				pmFolder.Item = append(pmFolder.Item, pmItem)
				pman.SetFolder(pmFolder)
			}
		}
		if len(path.Put.Tags) > 0 {
			if len(strings.TrimSpace(path.Put.Tags[0])) > 0 {
				pmItem := Swagger2PathToPostman2ApiItem(cfg, swag, url, "PUT", path.Put)
				pmFolderName := strings.TrimSpace(path.Put.Tags[0])
				pmFolder := pman.GetOrNewFolder(pmFolderName)
				pmFolder.Item = append(pmFolder.Item, pmItem)
				pman.SetFolder(pmFolder)
			}
		}
		if len(path.Delete.Tags) > 0 {
			if len(strings.TrimSpace(path.Delete.Tags[0])) > 0 {
				pmItem := Swagger2PathToPostman2ApiItem(cfg, swag, url, "DELETE", path.Delete)
				pmFolderName := strings.TrimSpace(path.Delete.Tags[0])
				pmFolder := pman.GetOrNewFolder(pmFolderName)
				pmFolder.Item = append(pmFolder.Item, pmItem)
				pman.SetFolder(pmFolder)
			}
		}
	}

	return pman
}

func Swagger2PathToPostman2ApiItem(cfg Configuration, swag swagger2.Specification, url string, method string, endpoint swagger2.Endpoint) postman2.ApiItem {
	item := postman2.ApiItem{}

	item.Name = endpoint.Summary

	item.Request = postman2.Request{
		Method: strings.ToUpper(method)}

	item.Request.URL = BuildPostmanURL(cfg, swag, url, endpoint)

	headers := []postman2.Header{}

	if len(endpoint.Consumes) > 0 {
		if len(strings.TrimSpace(endpoint.Consumes[0])) > 0 {
			headers = append(headers, postman2.Header{
				Key:   "Content-Type",
				Value: strings.TrimSpace(endpoint.Consumes[0])})
		}
	}
	if len(endpoint.Produces) > 0 {
		if len(strings.TrimSpace(endpoint.Produces[0])) > 0 {
			headers = append(headers, postman2.Header{
				Key:   "Accept",
				Value: strings.TrimSpace(endpoint.Consumes[0])})
		}
	}
	headers = append(headers, cfg.PostmanHeaders...)

	item.Request.Header = headers

	return item
}

func BuildPostmanURL(cfg Configuration, swag swagger2.Specification, swaggerUrl string, endpoint swagger2.Endpoint) postman2.URL {
	URLParts := []string{}

	// Set URL path parts
	if len(strings.TrimSpace(cfg.PostmanURLHostname)) > 0 {
		URLParts = append(URLParts, strings.TrimSpace(cfg.PostmanURLHostname))
	} else if len(strings.TrimSpace(swag.Host)) > 0 {
		URLParts = append(URLParts, strings.TrimSpace(swag.Host))
	}

	if len(strings.TrimSpace(swag.BasePath)) > 0 {
		URLParts = append(URLParts, strings.TrimSpace(swag.BasePath))
	}
	if len(strings.TrimSpace(swaggerUrl)) > 0 {
		URLParts = append(URLParts, strings.TrimSpace(swaggerUrl))
	}

	// Create URL
	rawPostmanUrl := strings.TrimSpace(strings.Join(URLParts, "/"))
	rx1 := regexp.MustCompile(`/+`)
	rawPostmanUrl = rx1.ReplaceAllString(rawPostmanUrl, "/")
	rx2 := regexp.MustCompile(`^/+`)
	rawPostmanUrl = rx2.ReplaceAllString(rawPostmanUrl, "")

	// Add URL Scheme
	if len(swag.Schemes) > 0 {
		for _, scheme := range swag.Schemes {
			if len(strings.TrimSpace(scheme)) > 0 {
				rawPostmanUrl = strings.Join([]string{scheme, rawPostmanUrl}, "://")
				break
			}
		}
	}

	rx3 := regexp.MustCompile(`(^|[^\{])\{([^\/\{\}]+)\}([^\}]|$)`)
	rawPostmanUrl = rx3.ReplaceAllString(rawPostmanUrl, "$1:$2$3")

	postmanUrl := postman2.NewURL(rawPostmanUrl)

	// Set Default URL Path Parameters
	rx4 := regexp.MustCompile(`^\s*(:(.+))\s*$`)

	for _, part := range postmanUrl.Path {
		rs4 := rx4.FindAllStringSubmatch(part, -1)
		if len(rs4) > 0 {
			baseVariable := rs4[0][2]
			//defaultValue := ""
			var defaultValue interface{}
			for _, parameter := range endpoint.Parameters {
				if parameter.Name == baseVariable {
					defaultValue = parameter.Default
					/*
						if len(strings.TrimSpace(parameter.Default)) > 0 {
							defaultValue = strings.TrimSpace(parameter.Default)
						}
					*/
					break
				}
			}
			postmanUrl.AddVariable(baseVariable, defaultValue)
		}
	}

	return postmanUrl
}
<|endoftext|>


<commit_before>package command

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"os"
	"strings"
	"testing"

	"github.com/mitchellh/cli"
)

func testOperatorUnsealCommand(tb testing.TB) (*cli.MockUi, *OperatorUnsealCommand) {
	tb.Helper()

	ui := cli.NewMockUi()
	return ui, &OperatorUnsealCommand{
		BaseCommand: &BaseCommand{
			UI: ui,
		},
	}
}

func TestOperatorUnsealCommand_Run(t *testing.T) {
	t.Parallel()

	t.Run("error_non_terminal", func(t *testing.T) {
		t.Parallel()

		client, closer := testVaultServer(t)
		defer closer()

		ui, cmd := testOperatorUnsealCommand(t)
		cmd.client = client
		cmd.testOutput = ioutil.Discard

		code := cmd.Run(nil)
		if exp := 1; code != exp {
			t.Errorf("expected %d to be %d", code, exp)
		}

		expected := "is not a terminal"
		combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
		if !strings.Contains(combined, expected) {
			t.Errorf("expected %q to contain %q", combined, expected)
		}
	})

	t.Run("reset", func(t *testing.T) {
		t.Parallel()

		client, keys, closer := testVaultServerUnseal(t)
		defer closer()

		// Seal so we can unseal
		if err := client.Sys().Seal(); err != nil {
			t.Fatal(err)
		}

		// Enter an unseal key
		if _, err := client.Sys().Unseal(keys[0]); err != nil {
			t.Fatal(err)
		}

		ui, cmd := testOperatorUnsealCommand(t)
		cmd.client = client
		cmd.testOutput = ioutil.Discard

		// Reset and check output
		code := cmd.Run([]string{
			"-reset",
		})
		if exp := 0; code != exp {
			t.Errorf("expected %d to be %d", code, exp)
		}
		expected := "0/3"
		combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
		if !strings.Contains(combined, expected) {
			t.Errorf("expected %q to contain %q", combined, expected)
		}
	})

	t.Run("full", func(t *testing.T) {
		t.Parallel()

		client, keys, closer := testVaultServerUnseal(t)
		defer closer()

		// Seal so we can unseal
		if err := client.Sys().Seal(); err != nil {
			t.Fatal(err)
		}

		for _, key := range keys {
			ui, cmd := testOperatorUnsealCommand(t)
			cmd.client = client
			cmd.testOutput = ioutil.Discard

			// Reset and check output
			code := cmd.Run([]string{
				key,
			})
			if exp := 0; code != exp {
				t.Errorf("expected %d to be %d: %s", code, exp, ui.ErrorWriter.String())
			}
		}

		status, err := client.Sys().SealStatus()
		if err != nil {
			t.Fatal(err)
		}
		if status.Sealed {
			t.Error("expected unsealed")
		}
	})

	t.Run("communication_failure", func(t *testing.T) {
		t.Parallel()

		client, closer := testVaultServerBad(t)
		defer closer()

		ui, cmd := testOperatorUnsealCommand(t)
		cmd.client = client

		code := cmd.Run([]string{
			"abcd",
		})
		if exp := 2; code != exp {
			t.Errorf("expected %d to be %d", code, exp)
		}

		expected := "Error unsealing: "
		combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
		if !strings.Contains(combined, expected) {
			t.Errorf("expected %q to contain %q", combined, expected)
		}
	})

	t.Run("no_tabs", func(t *testing.T) {
		t.Parallel()

		_, cmd := testOperatorUnsealCommand(t)
		assertNoTabs(t, cmd)
	})
}

func TestOperatorUnsealCommand_Format(t *testing.T) {
	defer func() {
		os.Setenv(EnvVaultCLINoColor, "")
	}()

	client, keys, closer := testVaultServerUnseal(t)
	defer closer()

	// Seal so we can unseal
	if err := client.Sys().Seal(); err != nil {
		t.Fatal(err)
	}

	stdout := bytes.NewBuffer(nil)
	stderr := bytes.NewBuffer(nil)
	runOpts := &RunOptions{
		Stdout: stdout,
		Stderr: stderr,
		Client: client,
	}

	args, format := setupEnv([]string{"unseal", "-format", "json"})
	if format != "json" {
		t.Fatalf("expected %q, got %q", "json", format)
	}

	// Unseal with one key
	code := RunCustom(append(args, []string{
		keys[0],
	}...), runOpts)
	if exp := 0; code != exp {
		t.Errorf("expected %d to be %d: %s", code, exp, stderr.String())
	}

	if !json.Valid(stdout.Bytes()) {
		t.Error("expected output to be valid JSON")
	}
}
<commit_msg>Fix test build<commit_after>package command

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"os"
	"strings"
	"testing"

	"github.com/mitchellh/cli"
)

func testOperatorUnsealCommand(tb testing.TB) (*cli.MockUi, *OperatorUnsealCommand) {
	tb.Helper()

	ui := cli.NewMockUi()
	return ui, &OperatorUnsealCommand{
		BaseCommand: &BaseCommand{
			UI: ui,
		},
	}
}

func TestOperatorUnsealCommand_Run(t *testing.T) {
	t.Parallel()

	t.Run("error_non_terminal", func(t *testing.T) {
		t.Parallel()

		client, closer := testVaultServer(t)
		defer closer()

		ui, cmd := testOperatorUnsealCommand(t)
		cmd.client = client
		cmd.testOutput = ioutil.Discard

		code := cmd.Run(nil)
		if exp := 1; code != exp {
			t.Errorf("expected %d to be %d", code, exp)
		}

		expected := "is not a terminal"
		combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
		if !strings.Contains(combined, expected) {
			t.Errorf("expected %q to contain %q", combined, expected)
		}
	})

	t.Run("reset", func(t *testing.T) {
		t.Parallel()

		client, keys, closer := testVaultServerUnseal(t)
		defer closer()

		// Seal so we can unseal
		if err := client.Sys().Seal(); err != nil {
			t.Fatal(err)
		}

		// Enter an unseal key
		if _, err := client.Sys().Unseal(keys[0]); err != nil {
			t.Fatal(err)
		}

		ui, cmd := testOperatorUnsealCommand(t)
		cmd.client = client
		cmd.testOutput = ioutil.Discard

		// Reset and check output
		code := cmd.Run([]string{
			"-reset",
		})
		if exp := 0; code != exp {
			t.Errorf("expected %d to be %d", code, exp)
		}
		expected := "0/3"
		combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
		if !strings.Contains(combined, expected) {
			t.Errorf("expected %q to contain %q", combined, expected)
		}
	})

	t.Run("full", func(t *testing.T) {
		t.Parallel()

		client, keys, closer := testVaultServerUnseal(t)
		defer closer()

		// Seal so we can unseal
		if err := client.Sys().Seal(); err != nil {
			t.Fatal(err)
		}

		for _, key := range keys {
			ui, cmd := testOperatorUnsealCommand(t)
			cmd.client = client
			cmd.testOutput = ioutil.Discard

			// Reset and check output
			code := cmd.Run([]string{
				key,
			})
			if exp := 0; code != exp {
				t.Errorf("expected %d to be %d: %s", code, exp, ui.ErrorWriter.String())
			}
		}

		status, err := client.Sys().SealStatus()
		if err != nil {
			t.Fatal(err)
		}
		if status.Sealed {
			t.Error("expected unsealed")
		}
	})

	t.Run("communication_failure", func(t *testing.T) {
		t.Parallel()

		client, closer := testVaultServerBad(t)
		defer closer()

		ui, cmd := testOperatorUnsealCommand(t)
		cmd.client = client

		code := cmd.Run([]string{
			"abcd",
		})
		if exp := 2; code != exp {
			t.Errorf("expected %d to be %d", code, exp)
		}

		expected := "Error unsealing: "
		combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
		if !strings.Contains(combined, expected) {
			t.Errorf("expected %q to contain %q", combined, expected)
		}
	})

	t.Run("no_tabs", func(t *testing.T) {
		t.Parallel()

		_, cmd := testOperatorUnsealCommand(t)
		assertNoTabs(t, cmd)
	})
}

func TestOperatorUnsealCommand_Format(t *testing.T) {
	defer func() {
		os.Setenv(EnvVaultCLINoColor, "")
	}()

	client, keys, closer := testVaultServerUnseal(t)
	defer closer()

	// Seal so we can unseal
	if err := client.Sys().Seal(); err != nil {
		t.Fatal(err)
	}

	stdout := bytes.NewBuffer(nil)
	stderr := bytes.NewBuffer(nil)
	runOpts := &RunOptions{
		Stdout: stdout,
		Stderr: stderr,
		Client: client,
	}

	args, format, _ := setupEnv([]string{"unseal", "-format", "json"})
	if format != "json" {
		t.Fatalf("expected %q, got %q", "json", format)
	}

	// Unseal with one key
	code := RunCustom(append(args, []string{
		keys[0],
	}...), runOpts)
	if exp := 0; code != exp {
		t.Errorf("expected %d to be %d: %s", code, exp, stderr.String())
	}

	if !json.Valid(stdout.Bytes()) {
		t.Error("expected output to be valid JSON")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"log"
	"net/http"

	"github.com/gorilla/mux"
)

var r *mux.Router

const ContactsBaseURL string = "http://localhost:3000/contacts/"

func init() {
	r = mux.NewRouter()
	r.HandleFunc("/contacts", getContactsHandler).Methods("GET")
	r.HandleFunc("/contacts", postContactsHandler).Methods("POST")
	r.HandleFunc("/contacts/{slug}", getContactHandler).Methods("GET")
}

// getContactsHandler returns a json response containing all
// the contacts.
//
// URL: GET /contacts
//
// For example, If there were only two contacts in total,
// GET /contacts and
// would yield the following response.
//
// Response:
// [
//  {
//    "id": "53a14760e3bdea4286000003",
//    "company": "Encom Inc.",
//    "person": "Sam Flynn",
//    "email": "samflynn@encom.com",
//    "phone": "103-345-456",
//    "skypeid": "sam_flynn",
//    "country": "USA"
//  },
//  {
//    "id": "53a14760e3bdea4286000004",
//    "company": "Encom Inc.",
//    "person": "Kevin Flynn",
//    "email": "kevinflynn@encom.com",
//    "phone": "234-877-988",
//    "skypeid": "kevin_flynn",
//    "country": "USA"
//  }
// ]
func getContactsHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	c, err := GetAllContacts()
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	enc := json.NewEncoder(w)
	if err = enc.Encode(c); err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// postContactsHandler creates a new contact in the database.
//
// URL: POST /contacts
//
// Request:
// {
//   "company": "Encom Inc.",
//   "person": "Sam Flynn",
//   "email": "samflynn@encom.com",
//   "phone": "103-345-456",
//   "skypeid": "sam_flynn",
//   "country": "USA"
// }
//
// Response:
// HTTP/1.1 201 Created
// Location: http://localhost:3000/contacts/sam-flynn
func postContactsHandler(w http.ResponseWriter, r *http.Request) {
	decoder := json.NewDecoder(r.Body)
	var c contact
	err := decoder.Decode(&c)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	n, err := NewContact(c.Company, c.Person, c.Email, c.Phone, c.SkypeId, c.Country)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	url := ContactsBaseURL + n.Slug
	w.Header().Set("Location", url)
	w.WriteHeader(http.StatusCreated)
}

// getContactHandler returns json data pertaining to a specific contact.
//
// URL: GET /contacts/{slug}
//
// For example,
// GET /contacts/flynn
//
// Response:
// {
//   "id": "53a15a07e3bdea53d0000002",
//   "company": "Encom Inc.",
//   "person": "Flynn",
//   "slug": "flynn"
//   "email": "flynn@encom.com",
//   "country": "USA"
// }
func getContactHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	vars := mux.Vars(r)
	slug := vars["slug"]
	c, err := GetContactBySlug(slug)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	enc := json.NewEncoder(w)
	if err = enc.Encode(c); err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}
<commit_msg>Add deleteContactHandler<commit_after>package main

import (
	"encoding/json"
	"log"
	"net/http"

	"github.com/gorilla/mux"
)

var r *mux.Router

const ContactsBaseURL string = "http://localhost:3000/contacts/"

func init() {
	r = mux.NewRouter()
	r.HandleFunc("/contacts", getContactsHandler).Methods("GET")
	r.HandleFunc("/contacts", postContactsHandler).Methods("POST")
	r.HandleFunc("/contacts/{slug}", getContactHandler).Methods("GET")
	r.HandleFunc("/contacts/{slug}", deleteContactHandler).Methods("DELETE")
}

// getContactsHandler returns a json response containing all
// the contacts.
//
// URL: GET /contacts
//
// For example, If there were only two contacts in total,
// GET /contacts and
// would yield the following response.
//
// Response:
// [
//  {
//    "id": "53a14760e3bdea4286000003",
//    "company": "Encom Inc.",
//    "person": "Sam Flynn",
//    "email": "samflynn@encom.com",
//    "phone": "103-345-456",
//    "skypeid": "sam_flynn",
//    "country": "USA"
//  },
//  {
//    "id": "53a14760e3bdea4286000004",
//    "company": "Encom Inc.",
//    "person": "Kevin Flynn",
//    "email": "kevinflynn@encom.com",
//    "phone": "234-877-988",
//    "skypeid": "kevin_flynn",
//    "country": "USA"
//  }
// ]
func getContactsHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	c, err := GetAllContacts()
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	enc := json.NewEncoder(w)
	if err = enc.Encode(c); err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// postContactsHandler creates a new contact in the database.
//
// URL: POST /contacts
//
// Request:
// {
//   "company": "Encom Inc.",
//   "person": "Sam Flynn",
//   "email": "samflynn@encom.com",
//   "phone": "103-345-456",
//   "skypeid": "sam_flynn",
//   "country": "USA"
// }
//
// Response:
// HTTP/1.1 201 Created
// Location: http://localhost:3000/contacts/sam-flynn
func postContactsHandler(w http.ResponseWriter, r *http.Request) {
	decoder := json.NewDecoder(r.Body)
	var c contact
	err := decoder.Decode(&c)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	n, err := NewContact(c.Company, c.Person, c.Email, c.Phone, c.SkypeId, c.Country)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	url := ContactsBaseURL + n.Slug
	w.Header().Set("Location", url)
	w.WriteHeader(http.StatusCreated)
}

// getContactHandler returns json data pertaining to a specific contact.
//
// URL: GET /contacts/{slug}
//
// For example,
// GET /contacts/flynn
//
// Response:
// {
//   "id": "53a15a07e3bdea53d0000002",
//   "company": "Encom Inc.",
//   "person": "Flynn",
//   "slug": "flynn"
//   "email": "flynn@encom.com",
//   "country": "USA"
// }
func getContactHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	vars := mux.Vars(r)
	slug := vars["slug"]
	c, err := GetContactBySlug(slug)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	enc := json.NewEncoder(w)
	if err = enc.Encode(c); err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func deleteContactHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	slug := vars["slug"]
	c, err := GetContactBySlug(slug)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	err := c.Delete()
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}
<|endoftext|>


<commit_before>package gopdf

import (
	"bytes"
	"strconv"
	"fmt"
)

type ContentObj struct { //impl IObj
	buffer bytes.Buffer
	stream  bytes.Buffer

	//text bytes.Buffer
	getRoot func()(*GoPdf)
}

func (me *ContentObj) Init(funcGetRoot func()(*GoPdf)) {
	me.getRoot = funcGetRoot
}

func (me *ContentObj) Build() {

	streamlen := me.stream.Len()
	me.buffer.WriteString("<<\n")
	me.buffer.WriteString("/Length "+strconv.Itoa(streamlen)+"\n")
	me.buffer.WriteString(">>\n")
	me.buffer.WriteString("stream\n")
	me.buffer.Write(me.stream.Bytes())
	me.buffer.WriteString("endstream\n")
}

func (me *ContentObj) GetType() string {
	return "Content"
}

func (me *ContentObj) GetObjBuff() *bytes.Buffer {
	return &(me.buffer)
}

func (me *ContentObj) AppendStream(rectangle *Rect,text string){

	fontSize := me.getRoot().Curr.Font_Size

	x := fmt.Sprintf("%0.2f",me.getRoot().Curr.X)
	y := fmt.Sprintf("%0.2f",me.getRoot().config.PageSize.H  - me.getRoot().Curr.Y - (float64(fontSize) *0.7) )

	me.stream.WriteString("BT\n")
	me.stream.WriteString(x+" "+y+" TD\n")
	me.stream.WriteString("/F"+strconv.Itoa( me.getRoot().Curr.Font_FontCount  + 1)+" "+ strconv.Itoa(fontSize)+" Tf\n")
	me.stream.WriteString("("+text+") Tj\n")
	me.stream.WriteString("ET\n")
	if rectangle == nil {
		me.getRoot().Curr.X += StrHelper_GetStringWidth(text,fontSize,me.getRoot().Curr.Font_IFont)
	}else{
		me.getRoot().Curr.X += rectangle.W
	}

}

func (me *ContentObj) AppendStreamLine(x1 float64 , y1 float64, x2 float64 , y2 float64){

	h := me.getRoot().config.PageSize.H
	me.stream.WriteString( fmt.Sprintf("%0.2f %0.2f m %0.2f %0.2f l s\n",x1,h - y1,x2,h - y2))
}

func (me *ContentObj) AppendUnderline(startX float64 , y float64,endX float64,endY float64, text string){

	h   := me.getRoot().config.PageSize.H
	ut  := me.getRoot().Curr.Font_IFont.GetUt()
	//up := me.getRoot().Curr.Font_IFont.GetUp()
	textH :=  ContentObj_CalTextHeight( me.getRoot().Curr.Font_Size)
	arg3 := float64(h) - float64( y) - textH  - textH*0.07
	arg4 := float64( -ut/1000*me.getRoot().Curr.Font_Size)
	me.stream.WriteString(fmt.Sprintf("%0.2f %0.2f %0.2f %0.2f re f\n",startX,arg3,endX - startX ,arg4))

}

func (me *ContentObj) AppendStreamSetLineWidth(w float64){

	me.stream.WriteString(fmt.Sprintf("%.2f w\n",w))

}

func (me *ContentObj) AppendStreamImage(iindex int,x float64,y float64,rect *Rect){
	h := me.getRoot().config.PageSize.H
	me.stream.WriteString(fmt.Sprintf("q %0.2f 0 0 %0.2f %0.2f %0.2f cm /I%d Do Q\n", rect.W, rect.H , x , h - ( y + rect.H)  ,iindex+1))
}

//cal text height
func ContentObj_CalTextHeight(fontsize int) float64{
	return (float64(fontsize) *0.7)
}
<commit_msg>fix underline width<commit_after>package gopdf

import (
	"bytes"
	"strconv"
	"fmt"
)

type ContentObj struct { //impl IObj
	buffer bytes.Buffer
	stream  bytes.Buffer

	//text bytes.Buffer
	getRoot func()(*GoPdf)
}

func (me *ContentObj) Init(funcGetRoot func()(*GoPdf)) {
	me.getRoot = funcGetRoot
}

func (me *ContentObj) Build() {

	streamlen := me.stream.Len()
	me.buffer.WriteString("<<\n")
	me.buffer.WriteString("/Length "+strconv.Itoa(streamlen)+"\n")
	me.buffer.WriteString(">>\n")
	me.buffer.WriteString("stream\n")
	me.buffer.Write(me.stream.Bytes())
	me.buffer.WriteString("endstream\n")
}

func (me *ContentObj) GetType() string {
	return "Content"
}

func (me *ContentObj) GetObjBuff() *bytes.Buffer {
	return &(me.buffer)
}

func (me *ContentObj) AppendStream(rectangle *Rect,text string){

	fontSize := me.getRoot().Curr.Font_Size

	x := fmt.Sprintf("%0.2f",me.getRoot().Curr.X)
	y := fmt.Sprintf("%0.2f",me.getRoot().config.PageSize.H  - me.getRoot().Curr.Y - (float64(fontSize) *0.7) )

	me.stream.WriteString("BT\n")
	me.stream.WriteString(x+" "+y+" TD\n")
	me.stream.WriteString("/F"+strconv.Itoa( me.getRoot().Curr.Font_FontCount  + 1)+" "+ strconv.Itoa(fontSize)+" Tf\n")
	me.stream.WriteString("("+text+") Tj\n")
	me.stream.WriteString("ET\n")
	if rectangle == nil {
		me.getRoot().Curr.X += StrHelper_GetStringWidth(text,fontSize,me.getRoot().Curr.Font_IFont)
	}else{
		me.getRoot().Curr.X += rectangle.W
	}

}

func (me *ContentObj) AppendStreamLine(x1 float64 , y1 float64, x2 float64 , y2 float64){

	h := me.getRoot().config.PageSize.H
	me.stream.WriteString( fmt.Sprintf("%0.2f %0.2f m %0.2f %0.2f l s\n",x1,h - y1,x2,h - y2))
}

func (me *ContentObj) AppendUnderline(startX float64 , y float64,endX float64,endY float64, text string){

	h   := me.getRoot().config.PageSize.H
	ut  := me.getRoot().Curr.Font_IFont.GetUt()
	//up := me.getRoot().Curr.Font_IFont.GetUp()
	textH :=  ContentObj_CalTextHeight( me.getRoot().Curr.Font_Size)
	arg3 := float64(h) - float64( y) - textH  - textH*0.07
	arg4 := (float64(ut)/1000.00) * float64(me.getRoot().Curr.Font_Size)
	me.stream.WriteString(fmt.Sprintf("%0.2f %0.2f %0.2f -%0.2f re f\n",startX,arg3,endX - startX ,arg4))

	//fmt.Printf(" ut : %d  arg4 : -%0.2f", ut,arg4)
}

func (me *ContentObj) AppendStreamSetLineWidth(w float64){

	me.stream.WriteString(fmt.Sprintf("%.2f w\n",w))

}

func (me *ContentObj) AppendStreamImage(iindex int,x float64,y float64,rect *Rect){
	h := me.getRoot().config.PageSize.H
	me.stream.WriteString(fmt.Sprintf("q %0.2f 0 0 %0.2f %0.2f %0.2f cm /I%d Do Q\n", rect.W, rect.H , x , h - ( y + rect.H)  ,iindex+1))
}

//cal text height
func ContentObj_CalTextHeight(fontsize int) float64{
	return (float64(fontsize) *0.7)
}
<|endoftext|>


<commit_before>package converter

import (
	"reflect"
	"testing"
)

func TestKrSpaKa_Comma(t *testing.T) {
	expectedComma := ';'
	k := NewKrSpaKa()
	if k.Comma() != expectedComma {
		t.Errorf("Field seperator is %q instead of expected %q", k.Comma(), expectedComma)
	}
}

func TestKrSpaKa_IsTransaction(t *testing.T) {
	type testpair struct {
		expected bool
		record   []string
	}

	tests := []testpair{
		{false, []string{}},
		{false, []string{"1", "2", "3", "4", "5", "6", "7"}},
		{false, []string{"Auftragskonto", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", ""}},
		{false, []string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "Umsatz vorgemerkt"}},
		{true, []string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17"}},
	}

	k := NewKrSpaKa()
	for _, pair := range tests {
		actual := k.IsTransaction(pair.record)
		if actual != pair.expected {
			t.Errorf("Result is '%v', but it should be '%v' for %q", actual, pair.expected, pair.record)
		}
	}
}

func TestKrSpaKa_Convert(t *testing.T) {
	type testpair struct {
		record   []string
		expected []string
	}

	tests := []testpair{
		{
			[]string{"123456789", "14.10.16", "14.10.16", "FOLGELASTSCHRIFT", "1212-3434 acommpany ", "XC352647657", "sfasfae-325678fsdgr", "2323462477", "", "", "", "ACOMPANY", "DE1234567891234", "YYYYAAAAA", "-12,99", "EUR", "Umsatz gebucht"},
			[]string{"14/10/2016", "ACOMPANY", "", "[FOLGELASTSCHRIFT] 1212-3434 acommpany ", "12.99", ""},
		}, {
			[]string{"123456789", "15.10.16", "16.10.16", "FOLGELASTSCHRIFT", "1212-3434 bcommpany ", "XC352647657", "sfasfae-325678fsdgr", "2323462477", "", "", "", "BCOMPANY", "DE1234567891234", "YYYYAAAAA", "3092,44", "EUR", "Umsatz gebucht"},
			[]string{"15/10/2016", "BCOMPANY", "", "[FOLGELASTSCHRIFT] 1212-3434 bcommpany ", "", "3092.44"},
		},
	}

	k := NewKrSpaKa()
	for _, pair := range tests {
		actual := k.Convert(pair.record)
		if !reflect.DeepEqual(actual, pair.expected) {
			t.Errorf("Actual record (%q) does't match expected record (%q) with input (%q)", actual, pair.expected, pair.record)
		}
	}
}
<commit_msg>Remove transaction type from "Memo"<commit_after>package converter

import (
	"reflect"
	"testing"
)

func TestKrSpaKa_Comma(t *testing.T) {
	expectedComma := ';'
	k := NewKrSpaKa()
	if k.Comma() != expectedComma {
		t.Errorf("Field seperator is %q instead of expected %q", k.Comma(), expectedComma)
	}
}

func TestKrSpaKa_IsTransaction(t *testing.T) {
	type testpair struct {
		expected bool
		record   []string
	}

	tests := []testpair{
		{false, []string{}},
		{false, []string{"1", "2", "3", "4", "5", "6", "7"}},
		{false, []string{"Auftragskonto", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", ""}},
		{false, []string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "Umsatz vorgemerkt"}},
		{true, []string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17"}},
	}

	k := NewKrSpaKa()
	for _, pair := range tests {
		actual := k.IsTransaction(pair.record)
		if actual != pair.expected {
			t.Errorf("Result is '%v', but it should be '%v' for %q", actual, pair.expected, pair.record)
		}
	}
}

func TestKrSpaKa_Convert(t *testing.T) {
	type testpair struct {
		record   []string
		expected []string
	}

	tests := []testpair{
		{
			[]string{"123456789", "14.10.16", "14.10.16", "FOLGELASTSCHRIFT", "1212-3434 acommpany ", "XC352647657", "sfasfae-325678fsdgr", "2323462477", "", "", "", "ACOMPANY", "DE1234567891234", "YYYYAAAAA", "-12,99", "EUR", "Umsatz gebucht"},
			[]string{"14/10/2016", "ACOMPANY", "", "1212-3434 acommpany ", "12.99", ""},
		}, {
			[]string{"123456789", "15.10.16", "16.10.16", "FOLGELASTSCHRIFT", "1212-3434 bcommpany ", "XC352647657", "sfasfae-325678fsdgr", "2323462477", "", "", "", "BCOMPANY", "DE1234567891234", "YYYYAAAAA", "3092,44", "EUR", "Umsatz gebucht"},
			[]string{"15/10/2016", "BCOMPANY", "", "1212-3434 bcommpany ", "", "3092.44"},
		},
	}

	k := NewKrSpaKa()
	for _, pair := range tests {
		actual := k.Convert(pair.record)
		if !reflect.DeepEqual(actual, pair.expected) {
			t.Errorf("Actual record (%q) does't match expected record (%q) with input (%q)", actual, pair.expected, pair.record)
		}
	}
}
<|endoftext|>


<commit_before>package strmatcher

import (
	"regexp"
	"sync"
	"time"

	"v2ray.com/core/common/task"
)

// Matcher is the interface to determine a string matches a pattern.
type Matcher interface {
	// Match returns true if the given string matches a predefined pattern.
	Match(string) bool
}

// Type is the type of the matcher.
type Type byte

const (
	// Full is the type of matcher that the input string must exactly equal to the pattern.
	Full Type = iota
	// Substr is the type of matcher that the input string must contain the pattern as a sub-string.
	Substr
	// Domain is the type of matcher that the input string must be a sub-domain or itself of the pattern.
	Domain
	// Regex is the type of matcher that the input string must matches the regular-expression pattern.
	Regex
)

// New creates a new Matcher based on the given pattern.
func (t Type) New(pattern string) (Matcher, error) {
	switch t {
	case Full:
		return fullMatcher(pattern), nil
	case Substr:
		return substrMatcher(pattern), nil
	case Domain:
		return domainMatcher(pattern), nil
	case Regex:
		r, err := regexp.Compile(pattern)
		if err != nil {
			return nil, err
		}
		return &regexMatcher{
			pattern: r,
		}, nil
	default:
		panic("Unknown type")
	}
}

// IndexMatcher is the interface for matching with a group of matchers.
type IndexMatcher interface {
	// Match returns the the index of a matcher that matches the input. It returns 0 if no such matcher exists.
	Match(input string) uint32
}

type matcherEntry struct {
	m  Matcher
	id uint32
}

// MatcherGroup is an implementation of IndexMatcher.
// Empty initialization works.
type MatcherGroup struct {
	count         uint32
	fullMatcher   FullMatcherGroup
	domainMatcher DomainMatcherGroup
	otherMatchers []matcherEntry
}

// Add adds a new Matcher into the MatcherGroup, and returns its index. The index will never be 0.
func (g *MatcherGroup) Add(m Matcher) uint32 {
	g.count++
	c := g.count

	switch tm := m.(type) {
	case fullMatcher:
		g.fullMatcher.addMatcher(tm, c)
	case domainMatcher:
		g.domainMatcher.addMatcher(tm, c)
	default:
		g.otherMatchers = append(g.otherMatchers, matcherEntry{
			m:  m,
			id: c,
		})
	}

	return c
}

// Match implements IndexMatcher.Match.
func (g *MatcherGroup) Match(pattern string) uint32 {
	if c := g.fullMatcher.Match(pattern); c > 0 {
		return c
	}

	if c := g.domainMatcher.Match(pattern); c > 0 {
		return c
	}

	for _, e := range g.otherMatchers {
		if e.m.Match(pattern) {
			return e.id
		}
	}

	return 0
}

// Size returns the number of matchers in the MatcherGroup.
func (g *MatcherGroup) Size() uint32 {
	return g.count
}

type cacheEntry struct {
	timestamp time.Time
	result    uint32
}

// CachedMatcherGroup is a IndexMatcher with cachable results.
type CachedMatcherGroup struct {
	sync.RWMutex
	group   *MatcherGroup
	cache   map[string]cacheEntry
	cleanup *task.Periodic
}

// NewCachedMatcherGroup creats a new CachedMatcherGroup.
func NewCachedMatcherGroup(g *MatcherGroup) *CachedMatcherGroup {
	r := &CachedMatcherGroup{
		group: g,
		cache: make(map[string]cacheEntry),
	}
	r.cleanup = &task.Periodic{
		Interval: time.Second * 30,
		Execute: func() error {
			r.Lock()
			defer r.Unlock()

			expire := time.Now().Add(-1 * time.Second * 120)
			for p, e := range r.cache {
				if e.timestamp.Before(expire) {
					delete(r.cache, p)
				}
			}

			return nil
		},
	}
	return r
}

// Match implements IndexMatcher.Match.
func (g *CachedMatcherGroup) Match(pattern string) uint32 {
	g.RLock()
	r, f := g.cache[pattern]
	g.RUnlock()
	if f {
		return r.result
	}

	mr := g.group.Match(pattern)

	g.Lock()
	g.cache[pattern] = cacheEntry{
		result:    mr,
		timestamp: time.Now(),
	}
	g.Unlock()

	return mr
}
<commit_msg>actually start the cleanup task<commit_after>package strmatcher

import (
	"regexp"
	"sync"
	"time"

	"v2ray.com/core/common"
	"v2ray.com/core/common/task"
)

// Matcher is the interface to determine a string matches a pattern.
type Matcher interface {
	// Match returns true if the given string matches a predefined pattern.
	Match(string) bool
}

// Type is the type of the matcher.
type Type byte

const (
	// Full is the type of matcher that the input string must exactly equal to the pattern.
	Full Type = iota
	// Substr is the type of matcher that the input string must contain the pattern as a sub-string.
	Substr
	// Domain is the type of matcher that the input string must be a sub-domain or itself of the pattern.
	Domain
	// Regex is the type of matcher that the input string must matches the regular-expression pattern.
	Regex
)

// New creates a new Matcher based on the given pattern.
func (t Type) New(pattern string) (Matcher, error) {
	switch t {
	case Full:
		return fullMatcher(pattern), nil
	case Substr:
		return substrMatcher(pattern), nil
	case Domain:
		return domainMatcher(pattern), nil
	case Regex:
		r, err := regexp.Compile(pattern)
		if err != nil {
			return nil, err
		}
		return &regexMatcher{
			pattern: r,
		}, nil
	default:
		panic("Unknown type")
	}
}

// IndexMatcher is the interface for matching with a group of matchers.
type IndexMatcher interface {
	// Match returns the the index of a matcher that matches the input. It returns 0 if no such matcher exists.
	Match(input string) uint32
}

type matcherEntry struct {
	m  Matcher
	id uint32
}

// MatcherGroup is an implementation of IndexMatcher.
// Empty initialization works.
type MatcherGroup struct {
	count         uint32
	fullMatcher   FullMatcherGroup
	domainMatcher DomainMatcherGroup
	otherMatchers []matcherEntry
}

// Add adds a new Matcher into the MatcherGroup, and returns its index. The index will never be 0.
func (g *MatcherGroup) Add(m Matcher) uint32 {
	g.count++
	c := g.count

	switch tm := m.(type) {
	case fullMatcher:
		g.fullMatcher.addMatcher(tm, c)
	case domainMatcher:
		g.domainMatcher.addMatcher(tm, c)
	default:
		g.otherMatchers = append(g.otherMatchers, matcherEntry{
			m:  m,
			id: c,
		})
	}

	return c
}

// Match implements IndexMatcher.Match.
func (g *MatcherGroup) Match(pattern string) uint32 {
	if c := g.fullMatcher.Match(pattern); c > 0 {
		return c
	}

	if c := g.domainMatcher.Match(pattern); c > 0 {
		return c
	}

	for _, e := range g.otherMatchers {
		if e.m.Match(pattern) {
			return e.id
		}
	}

	return 0
}

// Size returns the number of matchers in the MatcherGroup.
func (g *MatcherGroup) Size() uint32 {
	return g.count
}

type cacheEntry struct {
	timestamp time.Time
	result    uint32
}

// CachedMatcherGroup is a IndexMatcher with cachable results.
type CachedMatcherGroup struct {
	sync.RWMutex
	group   *MatcherGroup
	cache   map[string]cacheEntry
	cleanup *task.Periodic
}

// NewCachedMatcherGroup creats a new CachedMatcherGroup.
func NewCachedMatcherGroup(g *MatcherGroup) *CachedMatcherGroup {
	r := &CachedMatcherGroup{
		group: g,
		cache: make(map[string]cacheEntry),
	}
	r.cleanup = &task.Periodic{
		Interval: time.Second * 30,
		Execute: func() error {
			r.Lock()
			defer r.Unlock()

			expire := time.Now().Add(-1 * time.Second * 120)
			for p, e := range r.cache {
				if e.timestamp.Before(expire) {
					delete(r.cache, p)
				}
			}

			return nil
		},
	}
	common.Must(r.cleanup.Start())
	return r
}

// Match implements IndexMatcher.Match.
func (g *CachedMatcherGroup) Match(pattern string) uint32 {
	g.RLock()
	r, f := g.cache[pattern]
	g.RUnlock()
	if f {
		return r.result
	}

	mr := g.group.Match(pattern)

	g.Lock()
	g.cache[pattern] = cacheEntry{
		result:    mr,
		timestamp: time.Now(),
	}
	g.Unlock()

	return mr
}
<|endoftext|>


<commit_before>package util

import (
	"bytes"
	"context"
	"crypto/sha256"
	"crypto/x509"
	"encoding/json"
	"encoding/pem"
	"fmt"
	"io"
	"net"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
	"time"

	"golang.org/x/sys/unix"

	log "github.com/lxc/lxd/shared/log15"

	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/logger"
)

// WriteJSON encodes the body as JSON and sends it back to the client
func WriteJSON(w http.ResponseWriter, body interface{}, debug bool) error {
	var output io.Writer
	var captured *bytes.Buffer

	output = w
	if debug {
		captured = &bytes.Buffer{}
		output = io.MultiWriter(w, captured)
	}

	enc := json.NewEncoder(output)
	enc.SetEscapeHTML(false)
	err := enc.Encode(body)

	if captured != nil {
		shared.DebugJson(captured)
	}

	return err
}

// EtagHash hashes the provided data and returns the sha256
func EtagHash(data interface{}) (string, error) {
	etag := sha256.New()
	err := json.NewEncoder(etag).Encode(data)
	if err != nil {
		return "", err
	}

	return fmt.Sprintf("%x", etag.Sum(nil)), nil
}

// EtagCheck validates the hash of the current state with the hash
// provided by the client
func EtagCheck(r *http.Request, data interface{}) error {
	match := r.Header.Get("If-Match")
	if match == "" {
		return nil
	}

	match = strings.Trim(match, "\"")

	hash, err := EtagHash(data)
	if err != nil {
		return err
	}

	if hash != match {
		return fmt.Errorf("ETag doesn't match: %s vs %s", hash, match)
	}

	return nil
}

// HTTPClient returns an http.Client using the given certificate and proxy.
func HTTPClient(certificate string, proxy proxyFunc) (*http.Client, error) {
	var err error
	var cert *x509.Certificate

	if certificate != "" {
		certBlock, _ := pem.Decode([]byte(certificate))
		if certBlock == nil {
			return nil, fmt.Errorf("Invalid certificate")
		}

		cert, err = x509.ParseCertificate(certBlock.Bytes)
		if err != nil {
			return nil, err
		}
	}

	tlsConfig, err := shared.GetTLSConfig("", "", "", cert)
	if err != nil {
		return nil, err
	}

	tr := &http.Transport{
		TLSClientConfig:   tlsConfig,
		Dial:              shared.RFC3493Dialer,
		Proxy:             proxy,
		DisableKeepAlives: true,
	}

	myhttp := http.Client{
		Transport: tr,
	}

	// Setup redirect policy
	myhttp.CheckRedirect = func(req *http.Request, via []*http.Request) error {
		// Replicate the headers
		req.Header = via[len(via)-1].Header

		return nil
	}

	return &myhttp, nil
}

// A function capable of proxing an HTTP request.
type proxyFunc func(req *http.Request) (*url.URL, error)

// ContextAwareRequest is an interface implemented by http.Request starting
// from Go 1.8. It supports graceful cancellation using a context.
type ContextAwareRequest interface {
	WithContext(ctx context.Context) *http.Request
}

// CheckTrustState checks whether the given client certificate is trusted
// (i.e. it has a valid time span and it belongs to the given list of trusted
// certificates).
func CheckTrustState(cert x509.Certificate, trustedCerts map[string]x509.Certificate, certInfo *shared.CertInfo, trustCACertificates bool) (bool, string) {
	// Extra validity check (should have been caught by TLS stack)
	if time.Now().Before(cert.NotBefore) || time.Now().After(cert.NotAfter) {
		return false, ""
	}

	if certInfo != nil && trustCACertificates {
		ca := certInfo.CA()

		if ca != nil && cert.CheckSignatureFrom(ca) == nil {
			trusted := true

			// Check whether the certificate has been revoked.
			crl := certInfo.CRL()

			if crl != nil {
				for _, revoked := range crl.TBSCertList.RevokedCertificates {
					if cert.SerialNumber.Cmp(revoked.SerialNumber) == 0 {
						// Instead of returning false, we set trusted to false, allowing the client
						// to authenticate using the trust password.
						trusted = false
						break
					}
				}
			}

			if trusted {
				return true, shared.CertFingerprint(&cert)
			}
		}
	}

	for k, v := range trustedCerts {
		if bytes.Compare(cert.Raw, v.Raw) == 0 {
			logger.Debug("Found cert", log.Ctx{"name": k})
			return true, k
		}
	}

	return false, ""
}

// IsRecursionRequest checks whether the given HTTP request is marked with the
// "recursion" flag in its form values.
func IsRecursionRequest(r *http.Request) bool {
	recursionStr := r.FormValue("recursion")

	recursion, err := strconv.Atoi(recursionStr)
	if err != nil {
		return false
	}

	return recursion != 0
}

// ListenAddresses returns a list of host:port combinations at which
// this machine can be reached
func ListenAddresses(value string) ([]string, error) {
	addresses := make([]string, 0)

	if value == "" {
		return addresses, nil
	}

	localHost, localPort, err := net.SplitHostPort(value)
	if err != nil {
		localHost = value
		localPort = fmt.Sprintf("%d", shared.DefaultPort)
	}

	if localHost == "0.0.0.0" || localHost == "::" || localHost == "[::]" {
		ifaces, err := net.Interfaces()
		if err != nil {
			return addresses, err
		}

		for _, i := range ifaces {
			addrs, err := i.Addrs()
			if err != nil {
				continue
			}

			for _, addr := range addrs {
				var ip net.IP
				switch v := addr.(type) {
				case *net.IPNet:
					ip = v.IP
				case *net.IPAddr:
					ip = v.IP
				}

				if !ip.IsGlobalUnicast() {
					continue
				}

				if ip.To4() == nil {
					if localHost == "0.0.0.0" {
						continue
					}
					addresses = append(addresses, fmt.Sprintf("[%s]:%s", ip, localPort))
				} else {
					addresses = append(addresses, fmt.Sprintf("%s:%s", ip, localPort))
				}
			}
		}
	} else {
		if strings.Contains(localHost, ":") {
			addresses = append(addresses, fmt.Sprintf("[%s]:%s", localHost, localPort))
		} else {
			addresses = append(addresses, fmt.Sprintf("%s:%s", localHost, localPort))
		}
	}

	return addresses, nil
}

// GetListeners returns the socket-activated network listeners, if any.
//
// The 'start' parameter must be SystemdListenFDsStart, except in unit tests,
// see the docstring of SystemdListenFDsStart below.
func GetListeners(start int) []net.Listener {
	defer func() {
		os.Unsetenv("LISTEN_PID")
		os.Unsetenv("LISTEN_FDS")
	}()

	pid, err := strconv.Atoi(os.Getenv("LISTEN_PID"))
	if err != nil {
		return nil
	}

	if pid != os.Getpid() {
		return nil
	}

	fds, err := strconv.Atoi(os.Getenv("LISTEN_FDS"))
	if err != nil {
		return nil
	}

	listeners := []net.Listener{}

	for i := start; i < start+fds; i++ {
		unix.CloseOnExec(i)

		file := os.NewFile(uintptr(i), fmt.Sprintf("inherited-fd%d", i))
		listener, err := net.FileListener(file)
		if err != nil {
			continue
		}

		listeners = append(listeners, listener)
	}

	return listeners
}

// SystemdListenFDsStart is the number of the first file descriptor that might
// have been opened by systemd when socket activation is enabled. It's always 3
// in real-world usage (i.e. the first file descriptor opened after stdin,
// stdout and stderr), so this constant should always be the value passed to
// GetListeners, except for unit tests.
const SystemdListenFDsStart = 3

// IsJSONRequest returns true if the content type of the HTTP request is JSON.
func IsJSONRequest(r *http.Request) bool {
	for k, vs := range r.Header {
		if strings.ToLower(k) == "content-type" &&
			len(vs) == 1 && strings.ToLower(vs[0]) == "application/json" {
			return true
		}
	}

	return false
}
<commit_msg>lxd/util/http: Fix CheckTrustState to block access for revoked certificates that were formerly trusted<commit_after>package util

import (
	"bytes"
	"context"
	"crypto/sha256"
	"crypto/x509"
	"encoding/json"
	"encoding/pem"
	"fmt"
	"io"
	"net"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
	"time"

	"golang.org/x/sys/unix"

	log "github.com/lxc/lxd/shared/log15"

	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/logger"
)

// WriteJSON encodes the body as JSON and sends it back to the client
func WriteJSON(w http.ResponseWriter, body interface{}, debug bool) error {
	var output io.Writer
	var captured *bytes.Buffer

	output = w
	if debug {
		captured = &bytes.Buffer{}
		output = io.MultiWriter(w, captured)
	}

	enc := json.NewEncoder(output)
	enc.SetEscapeHTML(false)
	err := enc.Encode(body)

	if captured != nil {
		shared.DebugJson(captured)
	}

	return err
}

// EtagHash hashes the provided data and returns the sha256
func EtagHash(data interface{}) (string, error) {
	etag := sha256.New()
	err := json.NewEncoder(etag).Encode(data)
	if err != nil {
		return "", err
	}

	return fmt.Sprintf("%x", etag.Sum(nil)), nil
}

// EtagCheck validates the hash of the current state with the hash
// provided by the client
func EtagCheck(r *http.Request, data interface{}) error {
	match := r.Header.Get("If-Match")
	if match == "" {
		return nil
	}

	match = strings.Trim(match, "\"")

	hash, err := EtagHash(data)
	if err != nil {
		return err
	}

	if hash != match {
		return fmt.Errorf("ETag doesn't match: %s vs %s", hash, match)
	}

	return nil
}

// HTTPClient returns an http.Client using the given certificate and proxy.
func HTTPClient(certificate string, proxy proxyFunc) (*http.Client, error) {
	var err error
	var cert *x509.Certificate

	if certificate != "" {
		certBlock, _ := pem.Decode([]byte(certificate))
		if certBlock == nil {
			return nil, fmt.Errorf("Invalid certificate")
		}

		cert, err = x509.ParseCertificate(certBlock.Bytes)
		if err != nil {
			return nil, err
		}
	}

	tlsConfig, err := shared.GetTLSConfig("", "", "", cert)
	if err != nil {
		return nil, err
	}

	tr := &http.Transport{
		TLSClientConfig:   tlsConfig,
		Dial:              shared.RFC3493Dialer,
		Proxy:             proxy,
		DisableKeepAlives: true,
	}

	myhttp := http.Client{
		Transport: tr,
	}

	// Setup redirect policy
	myhttp.CheckRedirect = func(req *http.Request, via []*http.Request) error {
		// Replicate the headers
		req.Header = via[len(via)-1].Header

		return nil
	}

	return &myhttp, nil
}

// A function capable of proxing an HTTP request.
type proxyFunc func(req *http.Request) (*url.URL, error)

// ContextAwareRequest is an interface implemented by http.Request starting
// from Go 1.8. It supports graceful cancellation using a context.
type ContextAwareRequest interface {
	WithContext(ctx context.Context) *http.Request
}

// CheckTrustState checks whether the given client certificate is trusted
// (i.e. it has a valid time span and it belongs to the given list of trusted
// certificates).
func CheckTrustState(cert x509.Certificate, trustedCerts map[string]x509.Certificate, certInfo *shared.CertInfo, trustCACertificates bool) (bool, string) {
	// Extra validity check (should have been caught by TLS stack)
	if time.Now().Before(cert.NotBefore) || time.Now().After(cert.NotAfter) {
		return false, ""
	}

	if certInfo != nil && trustCACertificates {
		ca := certInfo.CA()

		if ca != nil && cert.CheckSignatureFrom(ca) == nil {
			// Check whether the certificate has been revoked.
			crl := certInfo.CRL()

			if crl != nil {
				for _, revoked := range crl.TBSCertList.RevokedCertificates {
					if cert.SerialNumber.Cmp(revoked.SerialNumber) == 0 {
						return false, "" // Certificate is revoked, so not trusted anymore.
					}
				}
			}

			// Certificate not revoked, so trust it as is signed by CA cert.
			return true, shared.CertFingerprint(&cert)
		}
	}

	// Check whether client certificate is in trust store.
	for k, v := range trustedCerts {
		if bytes.Compare(cert.Raw, v.Raw) == 0 {
			logger.Debug("Found cert", log.Ctx{"name": k})
			return true, k
		}
	}

	return false, ""
}

// IsRecursionRequest checks whether the given HTTP request is marked with the
// "recursion" flag in its form values.
func IsRecursionRequest(r *http.Request) bool {
	recursionStr := r.FormValue("recursion")

	recursion, err := strconv.Atoi(recursionStr)
	if err != nil {
		return false
	}

	return recursion != 0
}

// ListenAddresses returns a list of host:port combinations at which
// this machine can be reached
func ListenAddresses(value string) ([]string, error) {
	addresses := make([]string, 0)

	if value == "" {
		return addresses, nil
	}

	localHost, localPort, err := net.SplitHostPort(value)
	if err != nil {
		localHost = value
		localPort = fmt.Sprintf("%d", shared.DefaultPort)
	}

	if localHost == "0.0.0.0" || localHost == "::" || localHost == "[::]" {
		ifaces, err := net.Interfaces()
		if err != nil {
			return addresses, err
		}

		for _, i := range ifaces {
			addrs, err := i.Addrs()
			if err != nil {
				continue
			}

			for _, addr := range addrs {
				var ip net.IP
				switch v := addr.(type) {
				case *net.IPNet:
					ip = v.IP
				case *net.IPAddr:
					ip = v.IP
				}

				if !ip.IsGlobalUnicast() {
					continue
				}

				if ip.To4() == nil {
					if localHost == "0.0.0.0" {
						continue
					}
					addresses = append(addresses, fmt.Sprintf("[%s]:%s", ip, localPort))
				} else {
					addresses = append(addresses, fmt.Sprintf("%s:%s", ip, localPort))
				}
			}
		}
	} else {
		if strings.Contains(localHost, ":") {
			addresses = append(addresses, fmt.Sprintf("[%s]:%s", localHost, localPort))
		} else {
			addresses = append(addresses, fmt.Sprintf("%s:%s", localHost, localPort))
		}
	}

	return addresses, nil
}

// GetListeners returns the socket-activated network listeners, if any.
//
// The 'start' parameter must be SystemdListenFDsStart, except in unit tests,
// see the docstring of SystemdListenFDsStart below.
func GetListeners(start int) []net.Listener {
	defer func() {
		os.Unsetenv("LISTEN_PID")
		os.Unsetenv("LISTEN_FDS")
	}()

	pid, err := strconv.Atoi(os.Getenv("LISTEN_PID"))
	if err != nil {
		return nil
	}

	if pid != os.Getpid() {
		return nil
	}

	fds, err := strconv.Atoi(os.Getenv("LISTEN_FDS"))
	if err != nil {
		return nil
	}

	listeners := []net.Listener{}

	for i := start; i < start+fds; i++ {
		unix.CloseOnExec(i)

		file := os.NewFile(uintptr(i), fmt.Sprintf("inherited-fd%d", i))
		listener, err := net.FileListener(file)
		if err != nil {
			continue
		}

		listeners = append(listeners, listener)
	}

	return listeners
}

// SystemdListenFDsStart is the number of the first file descriptor that might
// have been opened by systemd when socket activation is enabled. It's always 3
// in real-world usage (i.e. the first file descriptor opened after stdin,
// stdout and stderr), so this constant should always be the value passed to
// GetListeners, except for unit tests.
const SystemdListenFDsStart = 3

// IsJSONRequest returns true if the content type of the HTTP request is JSON.
func IsJSONRequest(r *http.Request) bool {
	for k, vs := range r.Header {
		if strings.ToLower(k) == "content-type" &&
			len(vs) == 1 && strings.ToLower(vs[0]) == "application/json" {
			return true
		}
	}

	return false
}
<|endoftext|>


<commit_before>package main

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

	"github.com/docker/docker/pkg/integration/checker"
	"github.com/docker/engine-api/types"
	"github.com/go-check/check"
)

func (s *DockerSuite) TestApiImagesFilter(c *check.C) {
	testRequires(c, DaemonIsLinux)
	name := "utest:tag1"
	name2 := "utest/docker:tag2"
	name3 := "utest:5000/docker:tag3"
	for _, n := range []string{name, name2, name3} {
		dockerCmd(c, "tag", "busybox", n)
	}
	type image types.Image
	getImages := func(filter string) []image {
		v := url.Values{}
		v.Set("filter", filter)
		status, b, err := sockRequest("GET", "/images/json?"+v.Encode(), nil)
		c.Assert(err, checker.IsNil)
		c.Assert(status, checker.Equals, http.StatusOK)

		var images []image
		err = json.Unmarshal(b, &images)
		c.Assert(err, checker.IsNil)

		return images
	}

	//incorrect number of matches returned
	images := getImages("utest*/*")
	c.Assert(images[0].RepoTags, checker.HasLen, 2)

	images = getImages("utest")
	c.Assert(images[0].RepoTags, checker.HasLen, 1)

	images = getImages("utest*")
	c.Assert(images[0].RepoTags, checker.HasLen, 1)

	images = getImages("*5000*/*")
	c.Assert(images[0].RepoTags, checker.HasLen, 1)
}

func (s *DockerSuite) TestApiImagesSaveAndLoad(c *check.C) {
	testRequires(c, Network)
	testRequires(c, DaemonIsLinux)
	out, err := buildImage("saveandload", "FROM hello-world\nENV FOO bar", false)
	c.Assert(err, checker.IsNil)
	id := strings.TrimSpace(out)

	res, body, err := sockRequestRaw("GET", "/images/"+id+"/get", nil, "")
	c.Assert(err, checker.IsNil)
	defer body.Close()
	c.Assert(res.StatusCode, checker.Equals, http.StatusOK)

	dockerCmd(c, "rmi", id)

	res, loadBody, err := sockRequestRaw("POST", "/images/load", body, "application/x-tar")
	c.Assert(err, checker.IsNil)
	defer loadBody.Close()
	c.Assert(res.StatusCode, checker.Equals, http.StatusOK)

	inspectOut, _ := dockerCmd(c, "inspect", "--format='{{ .Id }}'", id)
	c.Assert(strings.TrimSpace(string(inspectOut)), checker.Equals, id, check.Commentf("load did not work properly"))
}

func (s *DockerSuite) TestApiImagesDelete(c *check.C) {
	testRequires(c, Network)
	testRequires(c, DaemonIsLinux)
	name := "test-api-images-delete"
	out, err := buildImage(name, "FROM hello-world\nENV FOO bar", false)
	c.Assert(err, checker.IsNil)
	id := strings.TrimSpace(out)

	dockerCmd(c, "tag", name, "test:tag1")

	status, _, err := sockRequest("DELETE", "/images/"+id, nil)
	c.Assert(err, checker.IsNil)
	c.Assert(status, checker.Equals, http.StatusConflict)

	status, _, err = sockRequest("DELETE", "/images/test:noexist", nil)
	c.Assert(err, checker.IsNil)
	c.Assert(status, checker.Equals, http.StatusNotFound) //Status Codes:404 – no such image

	status, _, err = sockRequest("DELETE", "/images/test:tag1", nil)
	c.Assert(err, checker.IsNil)
	c.Assert(status, checker.Equals, http.StatusOK)
}

func (s *DockerSuite) TestApiImagesHistory(c *check.C) {
	testRequires(c, Network)
	testRequires(c, DaemonIsLinux)
	name := "test-api-images-history"
	out, err := buildImage(name, "FROM hello-world\nENV FOO bar", false)
	c.Assert(err, checker.IsNil)

	id := strings.TrimSpace(out)

	status, body, err := sockRequest("GET", "/images/"+id+"/history", nil)
	c.Assert(err, checker.IsNil)
	c.Assert(status, checker.Equals, http.StatusOK)

	var historydata []types.ImageHistory
	err = json.Unmarshal(body, &historydata)
	c.Assert(err, checker.IsNil, check.Commentf("Error on unmarshal"))

	c.Assert(historydata, checker.Not(checker.HasLen), 0)
	c.Assert(historydata[0].Tags[0], checker.Equals, "test-api-images-history:latest")
}

// #14846
func (s *DockerSuite) TestApiImagesSearchJSONContentType(c *check.C) {
	testRequires(c, Network)

	res, b, err := sockRequestRaw("GET", "/images/search?term=test", nil, "application/json")
	c.Assert(err, check.IsNil)
	b.Close()
	c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
	c.Assert(res.Header.Get("Content-Type"), checker.Equals, "application/json")
}
<commit_msg>Windows CI: Porting for docker_api_images_test.go<commit_after>package main

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

	"github.com/docker/docker/pkg/integration/checker"
	"github.com/docker/engine-api/types"
	"github.com/go-check/check"
)

func (s *DockerSuite) TestApiImagesFilter(c *check.C) {
	name := "utest:tag1"
	name2 := "utest/docker:tag2"
	name3 := "utest:5000/docker:tag3"
	for _, n := range []string{name, name2, name3} {
		dockerCmd(c, "tag", "busybox", n)
	}
	type image types.Image
	getImages := func(filter string) []image {
		v := url.Values{}
		v.Set("filter", filter)
		status, b, err := sockRequest("GET", "/images/json?"+v.Encode(), nil)
		c.Assert(err, checker.IsNil)
		c.Assert(status, checker.Equals, http.StatusOK)

		var images []image
		err = json.Unmarshal(b, &images)
		c.Assert(err, checker.IsNil)

		return images
	}

	//incorrect number of matches returned
	images := getImages("utest*/*")
	c.Assert(images[0].RepoTags, checker.HasLen, 2)

	images = getImages("utest")
	c.Assert(images[0].RepoTags, checker.HasLen, 1)

	images = getImages("utest*")
	c.Assert(images[0].RepoTags, checker.HasLen, 1)

	images = getImages("*5000*/*")
	c.Assert(images[0].RepoTags, checker.HasLen, 1)
}

func (s *DockerSuite) TestApiImagesSaveAndLoad(c *check.C) {
	// TODO Windows to Windows CI: Investigate further why this test fails.
	testRequires(c, Network)
	testRequires(c, DaemonIsLinux)
	out, err := buildImage("saveandload", "FROM busybox\nENV FOO bar", false)
	c.Assert(err, checker.IsNil)
	id := strings.TrimSpace(out)

	res, body, err := sockRequestRaw("GET", "/images/"+id+"/get", nil, "")
	c.Assert(err, checker.IsNil)
	defer body.Close()
	c.Assert(res.StatusCode, checker.Equals, http.StatusOK)

	dockerCmd(c, "rmi", id)

	res, loadBody, err := sockRequestRaw("POST", "/images/load", body, "application/x-tar")
	c.Assert(err, checker.IsNil)
	defer loadBody.Close()
	c.Assert(res.StatusCode, checker.Equals, http.StatusOK)

	inspectOut, _ := dockerCmd(c, "inspect", "--format='{{ .Id }}'", id)
	c.Assert(strings.TrimSpace(string(inspectOut)), checker.Equals, id, check.Commentf("load did not work properly"))
}

func (s *DockerSuite) TestApiImagesDelete(c *check.C) {
	if daemonPlatform != "windows" {
		testRequires(c, Network)
	}
	name := "test-api-images-delete"
	out, err := buildImage(name, "FROM busybox\nENV FOO bar", false)
	c.Assert(err, checker.IsNil)
	id := strings.TrimSpace(out)

	dockerCmd(c, "tag", name, "test:tag1")

	status, _, err := sockRequest("DELETE", "/images/"+id, nil)
	c.Assert(err, checker.IsNil)
	c.Assert(status, checker.Equals, http.StatusConflict)

	status, _, err = sockRequest("DELETE", "/images/test:noexist", nil)
	c.Assert(err, checker.IsNil)
	c.Assert(status, checker.Equals, http.StatusNotFound) //Status Codes:404 – no such image

	status, _, err = sockRequest("DELETE", "/images/test:tag1", nil)
	c.Assert(err, checker.IsNil)
	c.Assert(status, checker.Equals, http.StatusOK)
}

func (s *DockerSuite) TestApiImagesHistory(c *check.C) {
	if daemonPlatform != "windows" {
		testRequires(c, Network)
	}
	name := "test-api-images-history"
	out, err := buildImage(name, "FROM busybox\nENV FOO bar", false)
	c.Assert(err, checker.IsNil)

	id := strings.TrimSpace(out)

	status, body, err := sockRequest("GET", "/images/"+id+"/history", nil)
	c.Assert(err, checker.IsNil)
	c.Assert(status, checker.Equals, http.StatusOK)

	var historydata []types.ImageHistory
	err = json.Unmarshal(body, &historydata)
	c.Assert(err, checker.IsNil, check.Commentf("Error on unmarshal"))

	c.Assert(historydata, checker.Not(checker.HasLen), 0)
	c.Assert(historydata[0].Tags[0], checker.Equals, "test-api-images-history:latest")
}

// #14846
func (s *DockerSuite) TestApiImagesSearchJSONContentType(c *check.C) {
	testRequires(c, Network)

	res, b, err := sockRequestRaw("GET", "/images/search?term=test", nil, "application/json")
	c.Assert(err, check.IsNil)
	b.Close()
	c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
	c.Assert(res.Header.Get("Content-Type"), checker.Equals, "application/json")
}
<|endoftext|>


<commit_before>package integration_test

import (
	"fmt"
	"io"
	"io/ioutil"
	"net/http"

	"github.com/pivotal-cf-experimental/bosh-bootloader/integration-test"
	"github.com/pivotal-cf-experimental/bosh-bootloader/integration-test/actors"
	"github.com/pivotal-cf-experimental/bosh-bootloader/testhelpers"
	"github.com/pivotal-cf-experimental/bosh-test/bosh"

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

const (
	ConcourseExampleManifestURL = "https://raw.githubusercontent.com/concourse/concourse/develop/manifests/concourse.yml"
	ConcourseReleaseURL         = "https://bosh.io/d/github.com/concourse/concourse"
	GardenReleaseURL            = "https://bosh.io/d/github.com/cloudfoundry-incubator/garden-runc-release"
	GardenReleaseName           = "garden-runc"
	StemcellURL                 = "https://bosh.io/d/stemcells/bosh-aws-xen-hvm-ubuntu-trusty-go_agent"
	StemcellName                = "bosh-aws-xen-hvm-ubuntu-trusty-go_agent"
)

var _ = Describe("bosh deployment tests", func() {
	var (
		bbl   actors.BBL
		aws   actors.AWS
		state integration.State
	)

	BeforeEach(func() {
		var err error
		configuration, err := integration.LoadConfig()
		Expect(err).NotTo(HaveOccurred())

		bbl = actors.NewBBL(configuration.StateFileDir, pathToBBL, configuration)
		aws = actors.NewAWS(configuration)
		state = integration.NewState(configuration.StateFileDir)
	})

	It("is able to deploy concourse", func() {
		bbl.Up()

		certPath, err := testhelpers.WriteContentsToTempFile(testhelpers.BBL_CERT)
		Expect(err).NotTo(HaveOccurred())

		keyPath, err := testhelpers.WriteContentsToTempFile(testhelpers.BBL_KEY)
		Expect(err).NotTo(HaveOccurred())

		bbl.CreateLB("concourse", certPath, keyPath, "")

		boshClient := bosh.NewClient(bosh.Config{
			URL:              bbl.DirectorAddress(),
			Username:         bbl.DirectorUsername(),
			Password:         bbl.DirectorPassword(),
			AllowInsecureSSL: true,
		})

		err = downloadAndUploadRelease(boshClient, ConcourseReleaseURL)
		Expect(err).NotTo(HaveOccurred())

		err = downloadAndUploadRelease(boshClient, GardenReleaseURL)
		Expect(err).NotTo(HaveOccurred())

		err = downloadAndUploadStemcell(boshClient, StemcellURL)
		Expect(err).NotTo(HaveOccurred())

		concourseExampleManifest, err := downloadConcourseExampleManifest()
		Expect(err).NotTo(HaveOccurred())

		info, err := boshClient.Info()
		Expect(err).NotTo(HaveOccurred())

		lbURL := fmt.Sprintf("http://%s", aws.LoadBalancers(state.StackName())["ConcourseLoadBalancerURL"])

		stemcell, err := boshClient.Stemcell(StemcellName)
		Expect(err).NotTo(HaveOccurred())

		concourseRelease, err := boshClient.Release("concourse")
		Expect(err).NotTo(HaveOccurred())

		gardenRelease, err := boshClient.Release(GardenReleaseName)
		Expect(err).NotTo(HaveOccurred())

		concourseManifestInputs := concourseManifestInputs{
			boshDirectorUUID:        info.UUID,
			webExternalURL:          lbURL,
			stemcellVersion:         stemcell.Latest(),
			concourseReleaseVersion: concourseRelease.Latest(),
			gardenReleaseVersion:    gardenRelease.Latest(),
		}
		concourseManifest, err := populateManifest(concourseExampleManifest, concourseManifestInputs)
		Expect(err).NotTo(HaveOccurred())

		boshClient.Deploy([]byte(concourseManifest))

		Eventually(func() ([]bosh.VM, error) {
			return boshClient.DeploymentVMs("concourse")
		}, "10m", "10s").Should(ConsistOf([]bosh.VM{
			{JobName: "worker", Index: 0, State: "running"},
			{JobName: "db", Index: 0, State: "running"},
			{JobName: "web", Index: 0, State: "running"},
		}))

		resp, err := http.Get(lbURL)
		Expect(err).NotTo(HaveOccurred())

		Expect(resp.StatusCode).To(Equal(http.StatusOK))

		body, err := ioutil.ReadAll(resp.Body)
		Expect(err).NotTo(HaveOccurred())

		Expect(string(body)).To(ContainSubstring("Log In - Concourse"))

		err = boshClient.DeleteDeployment("concourse")
		Expect(err).NotTo(HaveOccurred())

		bbl.Destroy()
	})
})

func downloadAndUploadStemcell(boshClient bosh.Client, stemcell string) error {
	file, size, err := download(stemcell)
	if err != nil {
		return err
	}

	_, err = boshClient.UploadStemcell(bosh.NewSizeReader(file, size))
	return err
}

func downloadAndUploadRelease(boshClient bosh.Client, release string) error {
	file, size, err := download(release)
	if err != nil {
		return err
	}

	_, err = boshClient.UploadRelease(bosh.NewSizeReader(file, size))
	return err
}

func downloadConcourseExampleManifest() (string, error) {
	resp, _, err := download(ConcourseExampleManifestURL)
	if err != nil {
		return "", err
	}

	rawRespBody, err := ioutil.ReadAll(resp)
	if err != nil {
		return "", err
	}

	return string(rawRespBody), nil
}

func download(location string) (io.Reader, int64, error) {
	resp, err := http.Get(location)
	if err != nil {
		return nil, 0, err
	}

	return resp.Body, resp.ContentLength, nil
}
<commit_msg>Use concourse manifest from master and not develop<commit_after>package integration_test

import (
	"fmt"
	"io"
	"io/ioutil"
	"net/http"

	"github.com/pivotal-cf-experimental/bosh-bootloader/integration-test"
	"github.com/pivotal-cf-experimental/bosh-bootloader/integration-test/actors"
	"github.com/pivotal-cf-experimental/bosh-bootloader/testhelpers"
	"github.com/pivotal-cf-experimental/bosh-test/bosh"

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

const (
	ConcourseExampleManifestURL = "https://raw.githubusercontent.com/concourse/concourse/master/manifests/concourse.yml"
	ConcourseReleaseURL         = "https://bosh.io/d/github.com/concourse/concourse"
	GardenReleaseURL            = "https://bosh.io/d/github.com/cloudfoundry-incubator/garden-runc-release"
	GardenReleaseName           = "garden-runc"
	StemcellURL                 = "https://bosh.io/d/stemcells/bosh-aws-xen-hvm-ubuntu-trusty-go_agent"
	StemcellName                = "bosh-aws-xen-hvm-ubuntu-trusty-go_agent"
)

var _ = Describe("bosh deployment tests", func() {
	var (
		bbl   actors.BBL
		aws   actors.AWS
		state integration.State
	)

	BeforeEach(func() {
		var err error
		configuration, err := integration.LoadConfig()
		Expect(err).NotTo(HaveOccurred())

		bbl = actors.NewBBL(configuration.StateFileDir, pathToBBL, configuration)
		aws = actors.NewAWS(configuration)
		state = integration.NewState(configuration.StateFileDir)
	})

	It("is able to deploy concourse", func() {
		bbl.Up()

		certPath, err := testhelpers.WriteContentsToTempFile(testhelpers.BBL_CERT)
		Expect(err).NotTo(HaveOccurred())

		keyPath, err := testhelpers.WriteContentsToTempFile(testhelpers.BBL_KEY)
		Expect(err).NotTo(HaveOccurred())

		bbl.CreateLB("concourse", certPath, keyPath, "")

		boshClient := bosh.NewClient(bosh.Config{
			URL:              bbl.DirectorAddress(),
			Username:         bbl.DirectorUsername(),
			Password:         bbl.DirectorPassword(),
			AllowInsecureSSL: true,
		})

		err = downloadAndUploadRelease(boshClient, ConcourseReleaseURL)
		Expect(err).NotTo(HaveOccurred())

		err = downloadAndUploadRelease(boshClient, GardenReleaseURL)
		Expect(err).NotTo(HaveOccurred())

		err = downloadAndUploadStemcell(boshClient, StemcellURL)
		Expect(err).NotTo(HaveOccurred())

		concourseExampleManifest, err := downloadConcourseExampleManifest()
		Expect(err).NotTo(HaveOccurred())

		info, err := boshClient.Info()
		Expect(err).NotTo(HaveOccurred())

		lbURL := fmt.Sprintf("http://%s", aws.LoadBalancers(state.StackName())["ConcourseLoadBalancerURL"])

		stemcell, err := boshClient.Stemcell(StemcellName)
		Expect(err).NotTo(HaveOccurred())

		concourseRelease, err := boshClient.Release("concourse")
		Expect(err).NotTo(HaveOccurred())

		gardenRelease, err := boshClient.Release(GardenReleaseName)
		Expect(err).NotTo(HaveOccurred())

		concourseManifestInputs := concourseManifestInputs{
			boshDirectorUUID:        info.UUID,
			webExternalURL:          lbURL,
			stemcellVersion:         stemcell.Latest(),
			concourseReleaseVersion: concourseRelease.Latest(),
			gardenReleaseVersion:    gardenRelease.Latest(),
		}
		concourseManifest, err := populateManifest(concourseExampleManifest, concourseManifestInputs)
		Expect(err).NotTo(HaveOccurred())

		boshClient.Deploy([]byte(concourseManifest))

		Eventually(func() ([]bosh.VM, error) {
			return boshClient.DeploymentVMs("concourse")
		}, "10m", "10s").Should(ConsistOf([]bosh.VM{
			{JobName: "worker", Index: 0, State: "running"},
			{JobName: "db", Index: 0, State: "running"},
			{JobName: "web", Index: 0, State: "running"},
		}))

		resp, err := http.Get(lbURL)
		Expect(err).NotTo(HaveOccurred())

		Expect(resp.StatusCode).To(Equal(http.StatusOK))

		body, err := ioutil.ReadAll(resp.Body)
		Expect(err).NotTo(HaveOccurred())

		Expect(string(body)).To(ContainSubstring("Log In - Concourse"))

		err = boshClient.DeleteDeployment("concourse")
		Expect(err).NotTo(HaveOccurred())

		bbl.Destroy()
	})
})

func downloadAndUploadStemcell(boshClient bosh.Client, stemcell string) error {
	file, size, err := download(stemcell)
	if err != nil {
		return err
	}

	_, err = boshClient.UploadStemcell(bosh.NewSizeReader(file, size))
	return err
}

func downloadAndUploadRelease(boshClient bosh.Client, release string) error {
	file, size, err := download(release)
	if err != nil {
		return err
	}

	_, err = boshClient.UploadRelease(bosh.NewSizeReader(file, size))
	return err
}

func downloadConcourseExampleManifest() (string, error) {
	resp, _, err := download(ConcourseExampleManifestURL)
	if err != nil {
		return "", err
	}

	rawRespBody, err := ioutil.ReadAll(resp)
	if err != nil {
		return "", err
	}

	return string(rawRespBody), nil
}

func download(location string) (io.Reader, int64, error) {
	resp, err := http.Get(location)
	if err != nil {
		return nil, 0, err
	}

	return resp.Body, resp.ContentLength, nil
}
<|endoftext|>