<commit_before>// this the file for the test (benchmarks are in another file)
package quadtree

import (
	"testing"
	"fmt"
)

// test function Level()
func TestLevel(t *testing.T) {

	cases := []struct {
		in Coord
		want int
	}{
		{0, 0},
		{1<<16, 1},
		{1<<16 + 34, 1},
		{21<<16 + 1 <<12, 21},
	}

	for _, c := range cases {
		got := c.in.Level()
		if( got != c.want) {
			t.Errorf("Level(%32b) == %d, want %d", c.in, got, c.want)
			t.Errorf("Level(|%8b|%8b|%8b|%8b|) == %d, want %d",
					0x000000FF & (c.in >> 24), 0x000000FF & (c.in >> 16), 0x000000FF & (c.in >> 8), 0x000000FF & c.in,
					got, c.want)
		}
	}
}

// test function "check integrity" of Coords
func TestCoordIntegrity( t *testing.T) {

	cases := []struct {
		in Coord
		want bool
	}{
		{ 0x00, true},
		{ 0x000000FF, false}, // at level 0, no bits are allowed for x or y
		{ 0x000a0001, false}, // level a is above 8
		{ 0x00070010, true}, // level 7 is OK
		{ 0x00070001, false}, // the last bit shall be 0
		{ 0x00070101, false}, // the last bit of x shall be 0
		{ 0x00080001, true}, // the last bit can be 1
		{ 0x000A0000, false},
		{ 0x0A0A0000, false}, // byte 0 shall be null
	}
	for rank, c := range cases {
		got := c.in.checkIntegrity()
		if( got != c.want) {
			// t.Errorf("checkIntegrity(%b) == %t, want %t", c.in, got, c.want)
			t.Errorf("case %d - checkIntegrity of |%8b|%8b|%8b|%8b|, %8x, level %d == %t, want %t",
					rank,
					0x000000FF & (c.in >> 24), 0x000000FF & (c.in >> 16), 0x000000FF & (c.in >> 8), 0x000000FF & c.in,
					c.in, c.in.Level(),
					got, c.want)
		}
	}
}

func TestSetX(t * testing.T) {
	cases := []struct {
		in Coord
		inX int
		want Coord
	}{
		{ 0x00080000, 8, 0x00080800 },
		{ 0x00080001, 8, 0x00080801 },
	}
	for _, c := range cases {
		coord := c.in
		coord.setX( c.inX)
		got := coord
		if( coord != c.want) {
			t.Errorf("\n setX(%d)\nin   %s\ngot  %s, \nwant %s",
			c.inX, &c.in, &got, &c.want)
		}
	}
}

func TestCoordString(t * testing.T) {

	c := Coord( 0x00080A0B)

	want := "{|       0|    1000|    1010|    1011|    80a0b}"

	got := fmt.Sprintf("%s", &c)

	if got != want { t.Errorf("\ngot  %s\nwant %s", got, want) }
}

func TestSetY(t * testing.T) {
	cases := []struct {
		in Coord
		inY int
		want Coord
	}{
		{ 0x00080000, 8, 0x00080008 },
	}
	for _, c := range cases {
		got := c.in
		got.setY( c.inY)
		if( got != c.want) {
			t.Errorf("%#v setY(%d) == |%8b|%8b|%8b|%8b|, got %8x, want %8x", c.in, c.inY,
			0x000000FF & (got >> 24), 0x000000FF & (got >> 16),
			0x000000FF & (got >> 8), 0x000000FF & got, got, c.want)
		}
	}
}

func TestUpdateNode(t * testing.T) {

	n := Node{}
	n.Bodies = make([](*Body), 2)
	n.Bodies[0] = &Body{ 0.5, 0.0, 1.0}
	n.Bodies[1] = &Body{ -0.5, 0.0, 1.0}

	want := Body{ 0.0, 0.0, 2.0}

	n.updateNode()
	if( n.Body != want) {
		t.Errorf("update node(%#v) want %#v, got %#v", n.Body, want, n)
	}
}

func TestGetCoord8(t * testing.T) {
	cases := []struct {
		in Body
		want Coord
	}{
		{ Body{0.0, 0.0, 0.0}, 0x00080000 },
		{ Body{0.0, 255.999, 255.999}, 0x0008FFFF },
	}
	for _, c := range cases {
		got := c.in.getCoord8()
		if( got != c.want) {
			t.Errorf("getCoord8(%#v) == |%8b|%8b|%8b|%8b|, %8x, want %8x", c.in,
			0x000000FF & (got >> 24), 0x000000FF & (got >> 16),
			0x000000FF & (got >> 8), 0x000000FF & got, got, c.want)
		}
	}
}

// check computation of nodes below
func TestNodesBelow(t * testing.T) {
	var q Quadtree
	var c Coord
	c.setLevel( 1)
	c.setX(128)
	c.setY(128)

	if ! c.checkIntegrity() { t.Errorf("invalid input %s", &c) }

	coordNW, coordNE, coordSW, coordSE := q.NodesBelow( c)
	fmt.Printf("\nin %s\nnw %s\nne %s\nsw %s\nse %s", &c, &coordNW, &coordNE, &coordSW, &coordSE)

	n_coordNW, coordNE, coordSW, coordSE := q.NodesBelow( coordNW)
	fmt.Printf("\n\nin %s\nnw %s\nne %s\nsw %s\nse %s", &coordNW, &n_coordNW, &coordNE, &coordSW, &coordSE)
}

func TestComputeLevel8(t * testing.T) {
	var q Quadtree
	var bodies []Body

	initQuadtree( &q, &bodies, 1)

	q.computeLevel8( bodies)
}

func TestSetupNodeLinks(t * testing.T) {
	var q Quadtree

	q.SetupNodeLinks()
}
<commit_msg>test now compile<commit_after>// this the file for the test (benchmarks are in another file)
package quadtree

import (
	"testing"
	"fmt"
)

// test function Level()
func TestLevel(t *testing.T) {

	cases := []struct {
		in Coord
		want int
	}{
		{0, 0},
		{1<<16, 1},
		{1<<16 + 34, 1},
		{21<<16 + 1 <<12, 21},
	}

	for _, c := range cases {
		got := c.in.Level()
		if( got != c.want) {
			t.Errorf("Level(%32b) == %d, want %d", c.in, got, c.want)
			t.Errorf("Level(|%8b|%8b|%8b|%8b|) == %d, want %d",
					0x000000FF & (c.in >> 24), 0x000000FF & (c.in >> 16), 0x000000FF & (c.in >> 8), 0x000000FF & c.in,
					got, c.want)
		}
	}
}

// test function "check integrity" of Coords
func TestCoordIntegrity( t *testing.T) {

	cases := []struct {
		in Coord
		want bool
	}{
		{ 0x00, true},
		{ 0x000000FF, false}, // at level 0, no bits are allowed for x or y
		{ 0x000a0001, false}, // level a is above 8
		{ 0x00070010, true}, // level 7 is OK
		{ 0x00070001, false}, // the last bit shall be 0
		{ 0x00070101, false}, // the last bit of x shall be 0
		{ 0x00080001, true}, // the last bit can be 1
		{ 0x000A0000, false},
		{ 0x0A0A0000, false}, // byte 0 shall be null
	}
	for rank, c := range cases {
		got := c.in.checkIntegrity()
		if( got != c.want) {
			// t.Errorf("checkIntegrity(%b) == %t, want %t", c.in, got, c.want)
			t.Errorf("case %d - checkIntegrity of |%8b|%8b|%8b|%8b|, %8x, level %d == %t, want %t",
					rank,
					0x000000FF & (c.in >> 24), 0x000000FF & (c.in >> 16), 0x000000FF & (c.in >> 8), 0x000000FF & c.in,
					c.in, c.in.Level(),
					got, c.want)
		}
	}
}

func TestSetX(t * testing.T) {
	cases := []struct {
		in Coord
		inX int
		want Coord
	}{
		{ 0x00080000, 8, 0x00080800 },
		{ 0x00080001, 8, 0x00080801 },
	}
	for _, c := range cases {
		coord := c.in
		coord.setX( c.inX)
		got := coord
		if( coord != c.want) {
			t.Errorf("\n setX(%d)\nin   %s\ngot  %s, \nwant %s",
			c.inX, &c.in, &got, &c.want)
		}
	}
}

func TestCoordString(t * testing.T) {

	c := Coord( 0x00080A0B)

	want := "{|       0|    1000|    1010|    1011|    80a0b}"

	got := fmt.Sprintf("%s", &c)

	if got != want { t.Errorf("\ngot  %s\nwant %s", got, want) }
}

func TestSetY(t * testing.T) {
	cases := []struct {
		in Coord
		inY int
		want Coord
	}{
		{ 0x00080000, 8, 0x00080008 },
	}
	for _, c := range cases {
		got := c.in
		got.setY( c.inY)
		if( got != c.want) {
			t.Errorf("%#v setY(%d) == |%8b|%8b|%8b|%8b|, got %8x, want %8x", c.in, c.inY,
			0x000000FF & (got >> 24), 0x000000FF & (got >> 16),
			0x000000FF & (got >> 8), 0x000000FF & got, got, c.want)
		}
	}
}

func TestUpdateNode(t * testing.T) {

	n := Node{}
	b1 := Body{ 0.5, 0.0, 1.0, n.first, nil}
	b2 := Body{ -0.5, 0.0, 1.0, &b1, nil}
	b1.next = &b2

	want := Body{ 0.0, 0.0, 2.0, nil, nil}

	n.updateNode()
	if( n.Body != want) {
		t.Errorf("update node(%#v) want %#v, got %#v", n.Body, want, n)
	}
}

func TestGetCoord8(t * testing.T) {
	cases := []struct {
		in Body
		want Coord
	}{
		{ Body{0.0, 0.0, 0.0, nil, nil}, 0x00080000 },
		{ Body{0.0, 255.999, 255.999, nil, nil}, 0x0008FFFF },
	}
	for _, c := range cases {
		got := c.in.getCoord8()
		if( got != c.want) {
			t.Errorf("getCoord8(%#v) == |%8b|%8b|%8b|%8b|, %8x, want %8x", c.in,
			0x000000FF & (got >> 24), 0x000000FF & (got >> 16),
			0x000000FF & (got >> 8), 0x000000FF & got, got, c.want)
		}
	}
}

// check computation of nodes below
func TestNodesBelow(t * testing.T) {
	var q Quadtree
	var c Coord
	c.setLevel( 1)
	c.setX(128)
	c.setY(128)

	if ! c.checkIntegrity() { t.Errorf("invalid input %s", &c) }

	coordNW, coordNE, coordSW, coordSE := q.NodesBelow( c)
	fmt.Printf("\nin %s\nnw %s\nne %s\nsw %s\nse %s", &c, &coordNW, &coordNE, &coordSW, &coordSE)

	n_coordNW, coordNE, coordSW, coordSE := q.NodesBelow( coordNW)
	fmt.Printf("\n\nin %s\nnw %s\nne %s\nsw %s\nse %s", &coordNW, &n_coordNW, &coordNE, &coordSW, &coordSE)
}

func TestComputeLevel8(t * testing.T) {
	var q Quadtree
	var bodies []Body

	initQuadtree( &q, &bodies, 1)

	q.computeLevel8( bodies)
}

func TestSetupNodeLinks(t * testing.T) {
	var q Quadtree

	q.SetupNodeLinks()
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"io"
	"testing"

	"github.com/flynn/lorne/types"
	"github.com/flynn/sampi/types"
	"github.com/technoweenie/grohl"
	"github.com/titanous/go-dockerclient"
)

type nullLogger struct{}

func (nullLogger) Log(grohl.Data) error { return nil }

func init() { grohl.SetLogger(nullLogger{}) }

type dockerClient struct {
	createErr error
	created   *docker.Config
	pulled    string
	started   bool
	hostConf  *docker.HostConfig
}

func (c *dockerClient) CreateContainer(config *docker.Config) (*docker.Container, error) {
	if c.createErr != nil {
		err := c.createErr
		c.createErr = nil
		return nil, err
	}
	c.created = config
	return &docker.Container{ID: "asdf"}, nil
}

func (c *dockerClient) StartContainer(id string, config *docker.HostConfig) error {
	if id != "asdf" {
		return errors.New("Invalid ID")
	}
	c.started = true
	c.hostConf = config
	return nil
}

func (c *dockerClient) PullImage(opts docker.PullImageOptions, w io.Writer) error {
	c.pulled = opts.Repository
	return nil
}

func testProcess(job *sampi.Job, t *testing.T) (*State, *dockerClient) {
	client := &dockerClient{}
	return testProcessWithOpts(job, "", client, t), client
}

func testProcessWithOpts(job *sampi.Job, extAddr string, client *dockerClient, t *testing.T) *State {
	jobs := make(chan *sampi.Job)
	done := make(chan struct{})
	ports := make(chan int)
	state := NewState()
	if client == nil {
		client = &dockerClient{}
	}
	go allocatePorts(ports, 500, 501)
	go func() {
		processJobs(jobs, extAddr, client, state, ports)
		close(done)
	}()
	jobs <- job
	close(jobs)
	<-done

	if client.created != job.Config {
		t.Error("job not created")
	}
	if job.Config.Name != "flynn-a" {
		t.Error("job name not set")
	}
	if !client.started {
		t.Error("job not started")
	}
	sjob := state.GetJob("a")
	if sjob == nil || sjob.StartedAt.IsZero() || sjob.Status != lorne.StatusRunning || sjob.ContainerID != "asdf" {
		t.Error("incorrect state")
	}

	return state
}

func TestProcessJob(t *testing.T) {
	testProcess(&sampi.Job{ID: "a", Config: &docker.Config{}}, t)
}

func TestProcessJobWithPort(t *testing.T) {
	job := &sampi.Job{TCPPorts: 1, ID: "a", Config: &docker.Config{}}
	_, client := testProcess(job, t)

	if len(job.Config.Env) == 0 || job.Config.Env[len(job.Config.Env)-1] != "PORT=500" {
		t.Error("port env not set")
	}
	if _, ok := job.Config.ExposedPorts["500/tcp"]; !ok {
		t.Error("exposed port not set")
	}
	if b := client.hostConf.PortBindings["500/tcp"]; len(b) == 0 || b[0].HostPort != "500" {
		t.Error("port binding not set")
	}
}

func TestProcessWithExtAddr(t *testing.T) {
	job := &sampi.Job{ID: "a", Config: &docker.Config{}}
	testProcessWithOpts(job, "10.10.10.1", nil, t)

	if !sliceHasString(job.Config.Env, "EXTERNAL_IP=10.10.10.1") {
		t.Error("EXTERNAL_IP not set")
	}
	if !sliceHasString(job.Config.Env, "DISCOVERD=10.10.10.1:1111") {
		t.Error("DISCOVERD not set")
	}
}

func sliceHasString(slice []string, str string) bool {
	for _, s := range slice {
		if s == str {
			return true
		}
	}
	return false
}

func TestProcessWithPull(t *testing.T) {
	job := &sampi.Job{ID: "a", Config: &docker.Config{Image: "test/foo"}}
	client := &dockerClient{createErr: docker.ErrNoSuchImage}
	testProcessWithOpts(job, "", client, t)

	if client.pulled != "test/foo" {
		t.Error("image not pulled")
	}
}
<commit_msg>host: Refactor test helpers<commit_after>package main

import (
	"errors"
	"io"
	"testing"

	"github.com/flynn/lorne/types"
	"github.com/flynn/sampi/types"
	"github.com/technoweenie/grohl"
	"github.com/titanous/go-dockerclient"
)

type nullLogger struct{}

func (nullLogger) Log(grohl.Data) error { return nil }

func init() { grohl.SetLogger(nullLogger{}) }

type dockerClient struct {
	createErr error
	created   *docker.Config
	pulled    string
	started   bool
	hostConf  *docker.HostConfig
}

func (c *dockerClient) CreateContainer(config *docker.Config) (*docker.Container, error) {
	if c.createErr != nil {
		err := c.createErr
		c.createErr = nil
		return nil, err
	}
	c.created = config
	return &docker.Container{ID: "asdf"}, nil
}

func (c *dockerClient) StartContainer(id string, config *docker.HostConfig) error {
	if id != "asdf" {
		return errors.New("Invalid ID")
	}
	c.started = true
	c.hostConf = config
	return nil
}

func (c *dockerClient) PullImage(opts docker.PullImageOptions, w io.Writer) error {
	c.pulled = opts.Repository
	return nil
}

func testProcess(job *sampi.Job, t *testing.T) (*State, *dockerClient) {
	client := &dockerClient{}
	return testProcessWithOpts(job, "", client, t), client
}

func testProcessWithOpts(job *sampi.Job, extAddr string, client *dockerClient, t *testing.T) *State {
	if client == nil {
		client = &dockerClient{}
	}
	state := processWithOpts(job, extAddr, client)

	if client.created != job.Config {
		t.Error("job not created")
	}
	if job.Config.Name != "flynn-a" {
		t.Error("job name not set")
	}
	if !client.started {
		t.Error("job not started")
	}
	sjob := state.GetJob("a")
	if sjob == nil || sjob.StartedAt.IsZero() || sjob.Status != lorne.StatusRunning || sjob.ContainerID != "asdf" {
		t.Error("incorrect state")
	}

	return state
}

func processWithOpts(job *sampi.Job, extAddr string, client *dockerClient) *State {
	jobs := make(chan *sampi.Job)
	done := make(chan struct{})
	ports := make(chan int)
	state := NewState()
	go allocatePorts(ports, 500, 501)
	go func() {
		processJobs(jobs, extAddr, client, state, ports)
		close(done)
	}()
	jobs <- job
	close(jobs)
	<-done
	return state
}

func TestProcessJob(t *testing.T) {
	testProcess(&sampi.Job{ID: "a", Config: &docker.Config{}}, t)
}

func TestProcessJobWithPort(t *testing.T) {
	job := &sampi.Job{TCPPorts: 1, ID: "a", Config: &docker.Config{}}
	_, client := testProcess(job, t)

	if len(job.Config.Env) == 0 || job.Config.Env[len(job.Config.Env)-1] != "PORT=500" {
		t.Error("port env not set")
	}
	if _, ok := job.Config.ExposedPorts["500/tcp"]; !ok {
		t.Error("exposed port not set")
	}
	if b := client.hostConf.PortBindings["500/tcp"]; len(b) == 0 || b[0].HostPort != "500" {
		t.Error("port binding not set")
	}
}

func TestProcessWithExtAddr(t *testing.T) {
	job := &sampi.Job{ID: "a", Config: &docker.Config{}}
	testProcessWithOpts(job, "10.10.10.1", nil, t)

	if !sliceHasString(job.Config.Env, "EXTERNAL_IP=10.10.10.1") {
		t.Error("EXTERNAL_IP not set")
	}
	if !sliceHasString(job.Config.Env, "DISCOVERD=10.10.10.1:1111") {
		t.Error("DISCOVERD not set")
	}
}

func sliceHasString(slice []string, str string) bool {
	for _, s := range slice {
		if s == str {
			return true
		}
	}
	return false
}

func TestProcessWithPull(t *testing.T) {
	job := &sampi.Job{ID: "a", Config: &docker.Config{Image: "test/foo"}}
	client := &dockerClient{createErr: docker.ErrNoSuchImage}
	testProcessWithOpts(job, "", client, t)

	if client.pulled != "test/foo" {
		t.Error("image not pulled")
	}
}
<|endoftext|>


<commit_before>package chatblast

type messageData struct {
	Name  string `json:"name,omitempty"`
	Value string `json:"value,omitempty"`
}

type Message struct {
	Msg    []messageData `json:"data,omitempty"`
	Text   string        `json:"txt,omitempty"`
	Cmd    string        `json:"cmd,omitempty"`
	Time   int64         `json:"time,omitempty"`
	RoomId string        `json:"rid,omitempty"`
	UserId string        `json:"uid,omitempty"`
	User   *User         `json:"user,omitempty"`
}
<commit_msg>Add Room to Message<commit_after>package chatblast

type messageData struct {
	Name  string `json:"name,omitempty"`
	Value string `json:"value,omitempty"`
}

type Message struct {
	Msg    []messageData `json:"data,omitempty"`
	Text   string        `json:"txt,omitempty"`
	Cmd    string        `json:"cmd,omitempty"`
	Time   int64         `json:"time,omitempty"`
	RoomId string        `json:"rid,omitempty"`
	UserId string        `json:"uid,omitempty"`
	User   *User         `json:"user,omitempty"`
	Room   *Room         `json:"room,omitempty"`
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"testing"
)

func TestNewURL(t *testing.T) {
	testCases := []struct {
		name, url, expect, host string
		setup                   func() func()
	}{{
		name:   "https", // Does nothing when the URL has scheme part
		url:    "https://github.com/motemen/pusheen-explorer",
		expect: "https://github.com/motemen/pusheen-explorer",
		host:   "github.com",
	}, {
		name:   "scp", // Convert SCP-like URL to SSH URL
		url:    "git@github.com:motemen/pusheen-explorer.git",
		expect: "ssh://git@github.com/motemen/pusheen-explorer.git",
		host:   "github.com",
	}, {
		name:   "scp with root",
		url:    "git@github.com:/motemen/pusheen-explorer.git",
		expect: "ssh://git@github.com//motemen/pusheen-explorer.git",
		host:   "github.com",
	}, {
		name:   "scp without user",
		url:    "github.com:motemen/pusheen-explorer.git",
		expect: "ssh://github.com/motemen/pusheen-explorer.git",
		host:   "github.com",
	}, {
		name:   "different name repository",
		url:    "motemen/ghq",
		expect: "https://github.com/motemen/ghq",
		host:   "github.com",
	}, {
		name:   "with authority repository",
		url:    "github.com/motemen/gore",
		expect: "https://github.com/motemen/gore",
		host:   "github.com",
	}, {
		name:   "with authority repository and go-import",
		url:    "golang.org/x/crypto",
		expect: "https://golang.org/x/crypto",
		host:   "golang.org",
	}, {
		name: "same name repository",
		setup: func() func() {
			key := "GITHUB_USER"
			orig := os.Getenv(key)
			os.Setenv(key, "ghq-test")
			return func() { os.Setenv(key, orig) }
		},
		url:    "same-name-ghq",
		expect: "https://github.com/ghq-test/same-name-ghq",
		host:   "github.com",
	}}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			if tc.setup != nil {
				defer tc.setup()()
			}
			repo, err := newURL(tc.url)
			if err != nil {
				t.Errorf("error should be nil but: %s", err)
			}
			if repo.String() != tc.expect {
				t.Errorf("url: got: %s, expect: %s", repo.String(), tc.expect)
			}
			if repo.Host != tc.host {
				t.Errorf("host: got: %s, expect: %s", repo.Host, tc.host)
			}
		})
	}
}

func TestConvertGitURLHTTPToSSH(t *testing.T) {
	testCases := []struct {
		url, expect string
	}{{
		url:    "https://github.com/motemen/pusheen-explorer",
		expect: "ssh://git@github.com/motemen/pusheen-explorer",
	}, {
		url:    "https://ghe.example.com/motemen/pusheen-explorer",
		expect: "ssh://git@ghe.example.com/motemen/pusheen-explorer",
	}, {
		url:    "https://motemen@ghe.example.com/motemen/pusheen-explorer",
		expect: "ssh://motemen@ghe.example.com/motemen/pusheen-explorer",
	}}

	for _, tc := range testCases {
		t.Run(tc.url, func(t *testing.T) {
			httpsURL, err := newURL(tc.url)
			if err != nil {
				t.Errorf("error should be nil but: %s", err)
			}
			sshURL, err := convertGitURLHTTPToSSH(httpsURL)
			if err != nil {
				t.Errorf("error should be nil but: %s", err)
			}
			if sshURL.String() != tc.expect {
				t.Errorf("got: %s, expect: %s", sshURL.String(), tc.expect)
			}
		})
	}
}
<commit_msg>add test for ghq.completeUser<commit_after>package main

import (
	"os"
	"testing"
)

func TestNewURL(t *testing.T) {
	testCases := []struct {
		name, url, expect, host string
		setup                   func() func()
	}{{
		name:   "https", // Does nothing when the URL has scheme part
		url:    "https://github.com/motemen/pusheen-explorer",
		expect: "https://github.com/motemen/pusheen-explorer",
		host:   "github.com",
	}, {
		name:   "scp", // Convert SCP-like URL to SSH URL
		url:    "git@github.com:motemen/pusheen-explorer.git",
		expect: "ssh://git@github.com/motemen/pusheen-explorer.git",
		host:   "github.com",
	}, {
		name:   "scp with root",
		url:    "git@github.com:/motemen/pusheen-explorer.git",
		expect: "ssh://git@github.com//motemen/pusheen-explorer.git",
		host:   "github.com",
	}, {
		name:   "scp without user",
		url:    "github.com:motemen/pusheen-explorer.git",
		expect: "ssh://github.com/motemen/pusheen-explorer.git",
		host:   "github.com",
	}, {
		name:   "different name repository",
		url:    "motemen/ghq",
		expect: "https://github.com/motemen/ghq",
		host:   "github.com",
	}, {
		name:   "with authority repository",
		url:    "github.com/motemen/gore",
		expect: "https://github.com/motemen/gore",
		host:   "github.com",
	}, {
		name:   "with authority repository and go-import",
		url:    "golang.org/x/crypto",
		expect: "https://golang.org/x/crypto",
		host:   "golang.org",
	}, {
		name: "fill username",
		setup: func() func() {
			key := "GITHUB_USER"
			orig := os.Getenv(key)
			os.Setenv(key, "ghq-test")
			return func() { os.Setenv(key, orig) }
		},
		url:    "same-name-ghq",
		expect: "https://github.com/ghq-test/same-name-ghq",
		host:   "github.com",
	}, {
		name: "same name repository",
		setup: func() func() {
			teardown, err := WithGitconfigFile(`[ghq]
completeUser = false`)
			if err != nil {
				panic(err)
			}
			return func() { teardown() }
		},
		url:    "peco",
		expect: "https://github.com/peco/peco",
		host:   "github.com",
	}}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			if tc.setup != nil {
				defer tc.setup()()
			}
			repo, err := newURL(tc.url)
			if err != nil {
				t.Errorf("error should be nil but: %s", err)
			}
			if repo.String() != tc.expect {
				t.Errorf("url: got: %s, expect: %s", repo.String(), tc.expect)
			}
			if repo.Host != tc.host {
				t.Errorf("host: got: %s, expect: %s", repo.Host, tc.host)
			}
		})
	}
}

func TestConvertGitURLHTTPToSSH(t *testing.T) {
	testCases := []struct {
		url, expect string
	}{{
		url:    "https://github.com/motemen/pusheen-explorer",
		expect: "ssh://git@github.com/motemen/pusheen-explorer",
	}, {
		url:    "https://ghe.example.com/motemen/pusheen-explorer",
		expect: "ssh://git@ghe.example.com/motemen/pusheen-explorer",
	}, {
		url:    "https://motemen@ghe.example.com/motemen/pusheen-explorer",
		expect: "ssh://motemen@ghe.example.com/motemen/pusheen-explorer",
	}}

	for _, tc := range testCases {
		t.Run(tc.url, func(t *testing.T) {
			httpsURL, err := newURL(tc.url)
			if err != nil {
				t.Errorf("error should be nil but: %s", err)
			}
			sshURL, err := convertGitURLHTTPToSSH(httpsURL)
			if err != nil {
				t.Errorf("error should be nil but: %s", err)
			}
			if sshURL.String() != tc.expect {
				t.Errorf("got: %s, expect: %s", sshURL.String(), tc.expect)
			}
		})
	}
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"net/http"
	"strings"

	"github.com/lxc/lxd/lxd/db"
	"github.com/lxc/lxd/lxd/project"
	"github.com/lxc/lxd/lxd/rbac"
	"github.com/lxc/lxd/lxd/response"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/logger"
)

var eventTypes = []string{"logging", "operation", "lifecycle"}
var privilegedEventTypes = []string{"logging"}

var eventsCmd = APIEndpoint{
	Path: "events",

	Get: APIEndpointAction{Handler: eventsGet, AccessHandler: allowAuthenticated},
}

type eventsServe struct {
	req *http.Request
	d   *Daemon
}

func (r *eventsServe) Render(w http.ResponseWriter) error {
	return eventsSocket(r.d, r.req, w)
}

func (r *eventsServe) String() string {
	return "event handler"
}

func eventsSocket(d *Daemon, r *http.Request, w http.ResponseWriter) error {
	allProjects := shared.IsTrue(queryParam(r, "all-projects"))
	projectQueryParam := queryParam(r, "project")
	if allProjects && projectQueryParam != "" {
		response.BadRequest(fmt.Errorf("Cannot specify a project when requesting events for all projects"))
		return nil
	}

	var projectName string
	if !allProjects {
		if projectQueryParam == "" {
			projectName = project.Default
		} else {
			projectName = projectQueryParam

			_, err := d.cluster.GetProject(projectName)
			if err != nil {
				if errors.Is(err, db.ErrNoSuchObject) {
					response.BadRequest(fmt.Errorf("Project %q not found", projectName)).Render(w)
				}

				return err
			}
		}
	}

	types := strings.Split(r.FormValue("type"), ",")
	if len(types) == 1 && types[0] == "" {
		types = []string{}
		for _, entry := range eventTypes {
			if !rbac.UserIsAdmin(r) && shared.StringInSlice(entry, privilegedEventTypes) {
				continue
			}

			types = append(types, entry)
		}
	}

	// Validate event types.
	for _, entry := range types {
		if !shared.StringInSlice(entry, eventTypes) {
			response.BadRequest(fmt.Errorf("'%s' isn't a supported event type", entry)).Render(w)
			return nil
		}
	}

	if shared.StringInSlice("logging", types) && !rbac.UserIsAdmin(r) {
		response.Forbidden(nil).Render(w)
		return nil
	}

	// Upgrade the connection to websocket
	c, err := shared.WebsocketUpgrader.Upgrade(w, r, nil)
	if err != nil {
		return err
	}
	defer c.Close() // This ensures the go routine below is ended when this function ends.

	// Get the current local serverName and store it for the events
	// We do that now to avoid issues with changes to the name and to limit
	// the number of DB access to just one per connection
	var serverName string
	err = d.cluster.Transaction(func(tx *db.ClusterTx) error {
		serverName, err = tx.GetLocalNodeName()
		return err
	})
	if err != nil {
		return err
	}

	// If this request is an internal one initiated by another node wanting
	// to watch the events on this node, set the listener to broadcast only
	// local events.
	listener, err := d.events.AddListener(projectName, allProjects, c, types, serverName, isClusterNotification(r))
	if err != nil {
		return err
	}

	logger.Debugf("New event listener: %s", listener.ID())
	listener.Wait(r.Context())
	logger.Debugf("Event listener finished: %s", listener.ID())

	return nil
}

// swagger:operation GET /1.0/events server events_get
//
// Get the event stream
//
// Connects to the event API using websocket.
//
// ---
// produces:
//   - application/json
// parameters:
//   - in: query
//     name: project
//     description: Project name
//     type: string
//     example: default
//   - in: query
//     name: type
//     description: Event type(s), comma separated (valid types are logging, operation or lifecycle)
//     type: string
//     example: logging,lifecycle
// responses:
//   "200":
//     description: Websocket message (JSON)
//     schema:
//       $ref: "#/definitions/Event"
//   "403":
//     $ref: "#/responses/Forbidden"
//   "500":
//     $ref: "#/responses/InternalServerError"
func eventsGet(d *Daemon, r *http.Request) response.Response {
	return &eventsServe{req: r, d: d}
}
<commit_msg>lxd/events: Removes duplicate event connection logging<commit_after>package main

import (
	"errors"
	"fmt"
	"net/http"
	"strings"

	"github.com/lxc/lxd/lxd/db"
	"github.com/lxc/lxd/lxd/project"
	"github.com/lxc/lxd/lxd/rbac"
	"github.com/lxc/lxd/lxd/response"
	"github.com/lxc/lxd/shared"
)

var eventTypes = []string{"logging", "operation", "lifecycle"}
var privilegedEventTypes = []string{"logging"}

var eventsCmd = APIEndpoint{
	Path: "events",

	Get: APIEndpointAction{Handler: eventsGet, AccessHandler: allowAuthenticated},
}

type eventsServe struct {
	req *http.Request
	d   *Daemon
}

func (r *eventsServe) Render(w http.ResponseWriter) error {
	return eventsSocket(r.d, r.req, w)
}

func (r *eventsServe) String() string {
	return "event handler"
}

func eventsSocket(d *Daemon, r *http.Request, w http.ResponseWriter) error {
	allProjects := shared.IsTrue(queryParam(r, "all-projects"))
	projectQueryParam := queryParam(r, "project")
	if allProjects && projectQueryParam != "" {
		response.BadRequest(fmt.Errorf("Cannot specify a project when requesting events for all projects"))
		return nil
	}

	var projectName string
	if !allProjects {
		if projectQueryParam == "" {
			projectName = project.Default
		} else {
			projectName = projectQueryParam

			_, err := d.cluster.GetProject(projectName)
			if err != nil {
				if errors.Is(err, db.ErrNoSuchObject) {
					response.BadRequest(fmt.Errorf("Project %q not found", projectName)).Render(w)
				}

				return err
			}
		}
	}

	types := strings.Split(r.FormValue("type"), ",")
	if len(types) == 1 && types[0] == "" {
		types = []string{}
		for _, entry := range eventTypes {
			if !rbac.UserIsAdmin(r) && shared.StringInSlice(entry, privilegedEventTypes) {
				continue
			}

			types = append(types, entry)
		}
	}

	// Validate event types.
	for _, entry := range types {
		if !shared.StringInSlice(entry, eventTypes) {
			response.BadRequest(fmt.Errorf("'%s' isn't a supported event type", entry)).Render(w)
			return nil
		}
	}

	if shared.StringInSlice("logging", types) && !rbac.UserIsAdmin(r) {
		response.Forbidden(nil).Render(w)
		return nil
	}

	// Upgrade the connection to websocket
	c, err := shared.WebsocketUpgrader.Upgrade(w, r, nil)
	if err != nil {
		return err
	}
	defer c.Close() // This ensures the go routine below is ended when this function ends.

	// Get the current local serverName and store it for the events
	// We do that now to avoid issues with changes to the name and to limit
	// the number of DB access to just one per connection
	var serverName string
	err = d.cluster.Transaction(func(tx *db.ClusterTx) error {
		serverName, err = tx.GetLocalNodeName()
		return err
	})
	if err != nil {
		return err
	}

	// If this request is an internal one initiated by another node wanting
	// to watch the events on this node, set the listener to broadcast only
	// local events.
	listener, err := d.events.AddListener(projectName, allProjects, c, types, serverName, isClusterNotification(r))
	if err != nil {
		return err
	}

	listener.Wait(r.Context())

	return nil
}

// swagger:operation GET /1.0/events server events_get
//
// Get the event stream
//
// Connects to the event API using websocket.
//
// ---
// produces:
//   - application/json
// parameters:
//   - in: query
//     name: project
//     description: Project name
//     type: string
//     example: default
//   - in: query
//     name: type
//     description: Event type(s), comma separated (valid types are logging, operation or lifecycle)
//     type: string
//     example: logging,lifecycle
// responses:
//   "200":
//     description: Websocket message (JSON)
//     schema:
//       $ref: "#/definitions/Event"
//   "403":
//     $ref: "#/responses/Forbidden"
//   "500":
//     $ref: "#/responses/InternalServerError"
func eventsGet(d *Daemon, r *http.Request) response.Response {
	return &eventsServe{req: r, d: d}
}
<|endoftext|>


<commit_before>package gardenrunner

import (
	"fmt"
	"net"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"syscall"
	"time"

	"code.cloudfoundry.org/garden/client"
	"code.cloudfoundry.org/garden/client/connection"
	"code.cloudfoundry.org/lager"
	"code.cloudfoundry.org/lager/lagertest"
	"github.com/onsi/ginkgo"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/ginkgomon"
)

type Runner struct {
	Command *exec.Cmd

	network string
	addr    string

	bin  string
	argv []string

	binPath    string
	rootFSPath string

	tmpdir    string
	graphRoot string
	graphPath string
}

func UseOldGardenRunc() bool {
	// return true if we are using old garden-runc (i.e. version <= 0.4)
	// we use the package name to distinguish them
	oldGardenRuncPath := os.Getenv("GARDEN_GOPATH") + "/src/github.com/cloudfoundry-incubator/guardian"
	if _, err := os.Stat(oldGardenRuncPath); os.IsNotExist(err) {
		return false
	}
	return true
}

func GardenServerPackageName() string {
	if UseOldGardenRunc() {
		return "github.com/cloudfoundry-incubator/guardian/cmd/guardian"
	}
	return "code.cloudfoundry.org/guardian/cmd/guardian"
}

func New(network, addr string, bin, binPath, rootFSPath, graphRoot string, argv ...string) *Runner {
	tmpDir := filepath.Join(
		os.TempDir(),
		fmt.Sprintf("test-garden-%d", ginkgo.GinkgoParallelNode()),
	)

	if graphRoot == "" {
		graphRoot = filepath.Join(tmpDir, "graph")
	}

	graphPath := filepath.Join(graphRoot, fmt.Sprintf("node-%d", ginkgo.GinkgoParallelNode()))

	return &Runner{
		network: network,
		addr:    addr,

		bin:  bin,
		argv: argv,

		binPath:    binPath,
		rootFSPath: rootFSPath,
		graphRoot:  graphRoot,
		graphPath:  graphPath,
		tmpdir:     tmpDir,
	}
}

func (r *Runner) Run(signals <-chan os.Signal, ready chan<- struct{}) error {
	logger := lagertest.NewTestLogger("garden-runner")

	if err := os.MkdirAll(r.tmpdir, 0755); err != nil {
		return err
	}

	depotPath := filepath.Join(r.tmpdir, "containers")
	snapshotsPath := filepath.Join(r.tmpdir, "snapshots")
	stateDirPath := filepath.Join(r.tmpdir, "state")

	if err := os.MkdirAll(depotPath, 0755); err != nil {
		return err
	}

	if err := os.MkdirAll(snapshotsPath, 0755); err != nil {
		return err
	}

	if err := os.MkdirAll(r.graphPath, 0755); err != nil {
		return err
	}

	var appendDefaultFlag = func(ar []string, key, value string) []string {
		for _, a := range r.argv {
			if a == key {
				return ar
			}
		}

		if value != "" {
			return append(ar, key, value)
		} else {
			return append(ar, key)
		}
	}

	gardenArgs := make([]string, len(r.argv))
	copy(gardenArgs, r.argv)

	gardenArgs = appendDefaultFlag(gardenArgs, "--depot", depotPath)
	gardenArgs = appendDefaultFlag(gardenArgs, "--graph", r.graphPath)
	gardenArgs = appendDefaultFlag(gardenArgs, "--tag", strconv.Itoa(ginkgo.GinkgoParallelNode()))

	if UseOldGardenRunc() {
		gardenArgs = appendDefaultFlag(gardenArgs, "--iodaemon-bin", r.binPath+"/iodaemon")
		gardenArgs = appendDefaultFlag(gardenArgs, "--kawasaki-bin", r.binPath+"/kawasaki")
	}

	gardenArgs = appendDefaultFlag(gardenArgs, "--init-bin", r.binPath+"/init")
	gardenArgs = appendDefaultFlag(gardenArgs, "--dadoo-bin", r.binPath+"/dadoo")
	gardenArgs = appendDefaultFlag(gardenArgs, "--nstar-bin", r.binPath+"/nstar")
	gardenArgs = appendDefaultFlag(gardenArgs, "--tar-bin", r.binPath+"/tar")
	gardenArgs = appendDefaultFlag(gardenArgs, "--runc-bin", r.binPath+"/runc")
	gardenArgs = appendDefaultFlag(gardenArgs, "--port-pool-start", strconv.Itoa(51000+(1000*ginkgo.GinkgoParallelNode())))
	gardenArgs = appendDefaultFlag(gardenArgs, "--port-pool-size", "1000")

	switch r.network {
	case "tcp":
		gardenArgs = appendDefaultFlag(gardenArgs, "--bind-ip", strings.Split(r.addr, ":")[0])
		gardenArgs = appendDefaultFlag(gardenArgs, "--bind-port", strings.Split(r.addr, ":")[1])
	case "unix":
		gardenArgs = appendDefaultFlag(gardenArgs, "--bind-socket", r.addr)
	}

	gardenArgs = appendDefaultFlag(gardenArgs, "--network-pool", fmt.Sprintf("10.250.%d.0/24", ginkgo.GinkgoParallelNode()))

	if r.rootFSPath != "" { //default-rootfs is an optional parameter
		gardenArgs = appendDefaultFlag(gardenArgs, "--default-rootfs", r.rootFSPath)
	}

	gardenArgs = appendDefaultFlag(gardenArgs, "--allow-host-access", "")

	var signal os.Signal

	r.Command = exec.Command(r.bin, gardenArgs...)

	process := ifrit.Invoke(&ginkgomon.Runner{
		Name:              "garden",
		Command:           r.Command,
		AnsiColorCode:     "31m",
		StartCheck:        "guardian.started",
		StartCheckTimeout: 30 * time.Second,
		Cleanup: func() {
			if signal == syscall.SIGQUIT {
				logger.Info("cleanup-subvolumes")

				// remove contents of subvolumes before deleting the subvolume
				if err := os.RemoveAll(r.graphPath); err != nil {
					logger.Error("remove graph", err)
				}

				logger.Info("cleanup-tempdirs")
				if err := os.RemoveAll(r.tmpdir); err != nil {
					logger.Error("cleanup-tempdirs-failed", err, lager.Data{"tmpdir": r.tmpdir})
				} else {
					logger.Info("tempdirs-removed")
				}
			}
		},
	})

	close(ready)

	for {
		select {
		case signal = <-signals:
			// SIGQUIT means clean up the containers, the garden process (SIGTERM) and the temporary directories
			// SIGKILL, SIGTERM and SIGINT are passed through to the garden process
			if signal == syscall.SIGQUIT {
				logger.Info("received-signal SIGQUIT")
				if err := r.destroyContainers(); err != nil {
					logger.Error("destroy-containers-failed", err)
					return err
				}
				logger.Info("destroyed-containers")
				process.Signal(syscall.SIGTERM)
			} else {
				logger.Info("received-signal", lager.Data{"signal": signal})
				process.Signal(signal)
			}

		case waitErr := <-process.Wait():
			logger.Info("process-exited")
			return waitErr
		}
	}
}

func (r *Runner) TryDial() error {
	conn, dialErr := net.DialTimeout(r.network, r.addr, 100*time.Millisecond)

	if dialErr == nil {
		conn.Close()
		return nil
	}

	return dialErr
}

func (r *Runner) NewClient() client.Client {
	return client.New(connection.New(r.network, r.addr))
}

func (r *Runner) destroyContainers() error {
	client := r.NewClient()

	containers, err := client.Containers(nil)
	if err != nil {
		return err
	}

	for _, container := range containers {
		err := client.Destroy(container.Handle())
		if err != nil {
			return err
		}
	}

	return nil
}
<commit_msg>Fix compilation error<commit_after>package gardenrunner

import (
	"fmt"
	"net"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"syscall"
	"time"

	"code.cloudfoundry.org/garden/client"
	"code.cloudfoundry.org/garden/client/connection"
	"code.cloudfoundry.org/lager"
	"code.cloudfoundry.org/lager/lagertest"
	"github.com/onsi/ginkgo"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/ginkgomon"
)

type Runner struct {
	Command *exec.Cmd

	network string
	addr    string

	bin  string
	argv []string

	binPath    string
	rootFSPath string

	tmpdir    string
	graphRoot string
	graphPath string
}

func UseOldGardenRunc() bool {
	// return true if we are using old garden-runc (i.e. version <= 0.4)
	// we use the package name to distinguish them
	oldGardenRuncPath := os.Getenv("GARDEN_GOPATH") + "/src/github.com/cloudfoundry-incubator/guardian"
	if _, err := os.Stat(oldGardenRuncPath); os.IsNotExist(err) {
		return false
	}
	return true
}

func GardenServerPackageName() string {
	if UseOldGardenRunc() {
		return "github.com/cloudfoundry-incubator/guardian/cmd/guardian"
	}
	return "code.cloudfoundry.org/guardian/cmd/guardian"
}

func New(network, addr string, bin, binPath, rootFSPath, graphRoot string, argv ...string) *Runner {
	tmpDir := filepath.Join(
		os.TempDir(),
		fmt.Sprintf("test-garden-%d", ginkgo.GinkgoParallelNode()),
	)

	if graphRoot == "" {
		graphRoot = filepath.Join(tmpDir, "graph")
	}

	graphPath := filepath.Join(graphRoot, fmt.Sprintf("node-%d", ginkgo.GinkgoParallelNode()))

	return &Runner{
		network: network,
		addr:    addr,

		bin:  bin,
		argv: argv,

		binPath:    binPath,
		rootFSPath: rootFSPath,
		graphRoot:  graphRoot,
		graphPath:  graphPath,
		tmpdir:     tmpDir,
	}
}

func (r *Runner) Run(signals <-chan os.Signal, ready chan<- struct{}) error {
	logger := lagertest.NewTestLogger("garden-runner")

	if err := os.MkdirAll(r.tmpdir, 0755); err != nil {
		return err
	}

	depotPath := filepath.Join(r.tmpdir, "containers")
	snapshotsPath := filepath.Join(r.tmpdir, "snapshots")

	if err := os.MkdirAll(depotPath, 0755); err != nil {
		return err
	}

	if err := os.MkdirAll(snapshotsPath, 0755); err != nil {
		return err
	}

	if err := os.MkdirAll(r.graphPath, 0755); err != nil {
		return err
	}

	var appendDefaultFlag = func(ar []string, key, value string) []string {
		for _, a := range r.argv {
			if a == key {
				return ar
			}
		}

		if value != "" {
			return append(ar, key, value)
		} else {
			return append(ar, key)
		}
	}

	gardenArgs := make([]string, len(r.argv))
	copy(gardenArgs, r.argv)

	gardenArgs = appendDefaultFlag(gardenArgs, "--depot", depotPath)
	gardenArgs = appendDefaultFlag(gardenArgs, "--graph", r.graphPath)
	gardenArgs = appendDefaultFlag(gardenArgs, "--tag", strconv.Itoa(ginkgo.GinkgoParallelNode()))

	if UseOldGardenRunc() {
		gardenArgs = appendDefaultFlag(gardenArgs, "--iodaemon-bin", r.binPath+"/iodaemon")
		gardenArgs = appendDefaultFlag(gardenArgs, "--kawasaki-bin", r.binPath+"/kawasaki")
	}

	gardenArgs = appendDefaultFlag(gardenArgs, "--init-bin", r.binPath+"/init")
	gardenArgs = appendDefaultFlag(gardenArgs, "--dadoo-bin", r.binPath+"/dadoo")
	gardenArgs = appendDefaultFlag(gardenArgs, "--nstar-bin", r.binPath+"/nstar")
	gardenArgs = appendDefaultFlag(gardenArgs, "--tar-bin", r.binPath+"/tar")
	gardenArgs = appendDefaultFlag(gardenArgs, "--runc-bin", r.binPath+"/runc")
	gardenArgs = appendDefaultFlag(gardenArgs, "--port-pool-start", strconv.Itoa(51000+(1000*ginkgo.GinkgoParallelNode())))
	gardenArgs = appendDefaultFlag(gardenArgs, "--port-pool-size", "1000")

	switch r.network {
	case "tcp":
		gardenArgs = appendDefaultFlag(gardenArgs, "--bind-ip", strings.Split(r.addr, ":")[0])
		gardenArgs = appendDefaultFlag(gardenArgs, "--bind-port", strings.Split(r.addr, ":")[1])
	case "unix":
		gardenArgs = appendDefaultFlag(gardenArgs, "--bind-socket", r.addr)
	}

	gardenArgs = appendDefaultFlag(gardenArgs, "--network-pool", fmt.Sprintf("10.250.%d.0/24", ginkgo.GinkgoParallelNode()))

	if r.rootFSPath != "" { //default-rootfs is an optional parameter
		gardenArgs = appendDefaultFlag(gardenArgs, "--default-rootfs", r.rootFSPath)
	}

	gardenArgs = appendDefaultFlag(gardenArgs, "--allow-host-access", "")

	var signal os.Signal

	r.Command = exec.Command(r.bin, gardenArgs...)

	process := ifrit.Invoke(&ginkgomon.Runner{
		Name:              "garden",
		Command:           r.Command,
		AnsiColorCode:     "31m",
		StartCheck:        "guardian.started",
		StartCheckTimeout: 30 * time.Second,
		Cleanup: func() {
			if signal == syscall.SIGQUIT {
				logger.Info("cleanup-subvolumes")

				// remove contents of subvolumes before deleting the subvolume
				if err := os.RemoveAll(r.graphPath); err != nil {
					logger.Error("remove graph", err)
				}

				logger.Info("cleanup-tempdirs")
				if err := os.RemoveAll(r.tmpdir); err != nil {
					logger.Error("cleanup-tempdirs-failed", err, lager.Data{"tmpdir": r.tmpdir})
				} else {
					logger.Info("tempdirs-removed")
				}
			}
		},
	})

	close(ready)

	for {
		select {
		case signal = <-signals:
			// SIGQUIT means clean up the containers, the garden process (SIGTERM) and the temporary directories
			// SIGKILL, SIGTERM and SIGINT are passed through to the garden process
			if signal == syscall.SIGQUIT {
				logger.Info("received-signal SIGQUIT")
				if err := r.destroyContainers(); err != nil {
					logger.Error("destroy-containers-failed", err)
					return err
				}
				logger.Info("destroyed-containers")
				process.Signal(syscall.SIGTERM)
			} else {
				logger.Info("received-signal", lager.Data{"signal": signal})
				process.Signal(signal)
			}

		case waitErr := <-process.Wait():
			logger.Info("process-exited")
			return waitErr
		}
	}
}

func (r *Runner) TryDial() error {
	conn, dialErr := net.DialTimeout(r.network, r.addr, 100*time.Millisecond)

	if dialErr == nil {
		conn.Close()
		return nil
	}

	return dialErr
}

func (r *Runner) NewClient() client.Client {
	return client.New(connection.New(r.network, r.addr))
}

func (r *Runner) destroyContainers() error {
	client := r.NewClient()

	containers, err := client.Containers(nil)
	if err != nil {
		return err
	}

	for _, container := range containers {
		err := client.Destroy(container.Handle())
		if err != nil {
			return err
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package libp2pwebtransport

import (
	"context"
	"crypto/tls"
	"errors"
	"net"
	"net/http"
	"time"

	tpt "github.com/libp2p/go-libp2p-core/transport"

	noise "github.com/libp2p/go-libp2p-noise"

	"github.com/lucas-clemente/quic-go/http3"
	"github.com/marten-seemann/webtransport-go"
	ma "github.com/multiformats/go-multiaddr"
	manet "github.com/multiformats/go-multiaddr/net"
)

var errClosed = errors.New("closed")

const queueLen = 16
const handshakeTimeout = 10 * time.Second

type listener struct {
	transport   tpt.Transport
	noise       *noise.Transport
	certManager *certManager

	server webtransport.Server

	ctx       context.Context
	ctxCancel context.CancelFunc

	serverClosed chan struct{} // is closed when server.Serve returns

	addr      net.Addr
	multiaddr ma.Multiaddr

	queue chan *webtransport.Conn
}

var _ tpt.Listener = &listener{}

func newListener(laddr ma.Multiaddr, transport tpt.Transport, noise *noise.Transport, certManager *certManager) (tpt.Listener, error) {
	network, addr, err := manet.DialArgs(laddr)
	if err != nil {
		return nil, err
	}
	udpAddr, err := net.ResolveUDPAddr(network, addr)
	if err != nil {
		return nil, err
	}
	udpConn, err := net.ListenUDP(network, udpAddr)
	if err != nil {
		return nil, err
	}
	localMultiaddr, err := toWebtransportMultiaddr(udpConn.LocalAddr())
	if err != nil {
		return nil, err
	}
	ln := &listener{
		transport:    transport,
		noise:        noise,
		certManager:  certManager,
		queue:        make(chan *webtransport.Conn, queueLen),
		serverClosed: make(chan struct{}),
		addr:         udpConn.LocalAddr(),
		multiaddr:    localMultiaddr,
		server: webtransport.Server{
			H3: http3.Server{
				Server: &http.Server{
					TLSConfig: &tls.Config{GetConfigForClient: func(*tls.ClientHelloInfo) (*tls.Config, error) {
						return certManager.GetConfig(), nil
					}},
				},
			},
		},
	}
	ln.ctx, ln.ctxCancel = context.WithCancel(context.Background())
	mux := http.NewServeMux()
	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Hello, world!"))
	})
	mux.HandleFunc(webtransportHTTPEndpoint, func(w http.ResponseWriter, r *http.Request) {
		// TODO: check ?type=multistream URL param
		c, err := ln.server.Upgrade(w, r)
		if err != nil {
			w.WriteHeader(500)
			return
		}
		// TODO: handle queue overflow
		ln.queue <- c
	})
	ln.server.H3.Handler = mux
	go func() {
		defer close(ln.serverClosed)
		defer func() { udpConn.Close() }()
		if err := ln.server.Serve(udpConn); err != nil {
			// TODO: only output if the server hasn't been closed
			log.Debugw("serving failed", "addr", udpConn.LocalAddr(), "error", err)
		}
	}()
	return ln, nil
}

func (l *listener) Accept() (tpt.CapableConn, error) {
	queue := make(chan tpt.CapableConn, queueLen)
	for {
		select {
		case <-l.ctx.Done():
			return nil, errClosed
		default:
		}

		var c *webtransport.Conn
		select {
		case c = <-l.queue:
			go func(c *webtransport.Conn) {
				ctx, cancel := context.WithTimeout(l.ctx, handshakeTimeout)
				defer cancel()
				conn, err := l.handshake(ctx, c)
				if err != nil {
					log.Debugw("handshake failed", "error", err)
					c.Close()
					return
				}
				// TODO: handle queue overflow
				queue <- conn
			}(c)
		case conn := <-queue:
			return conn, nil
		case <-l.ctx.Done():
			return nil, errClosed
		}
	}
}

func (l *listener) handshake(ctx context.Context, c *webtransport.Conn) (tpt.CapableConn, error) {
	str, err := c.AcceptStream(ctx)
	if err != nil {
		return nil, err
	}
	conn, err := l.noise.SecureInbound(ctx, &webtransportStream{Stream: str, wconn: c}, "")
	if err != nil {
		return nil, err
	}
	return newConn(l.transport, c, conn.LocalPrivateKey(), conn.RemotePublicKey())
}

func (l *listener) Addr() net.Addr {
	return l.addr
}

func (l *listener) Multiaddr() ma.Multiaddr {
	return l.multiaddr.Encapsulate(l.certManager.AddrComponent())
}

func (l *listener) Close() error {
	l.ctxCancel()
	err := l.server.Close()
	<-l.serverClosed
	return err
}
<commit_msg>chore: update webtransport-go<commit_after>package libp2pwebtransport

import (
	"context"
	"crypto/tls"
	"errors"
	"net"
	"net/http"
	"time"

	tpt "github.com/libp2p/go-libp2p-core/transport"

	noise "github.com/libp2p/go-libp2p-noise"

	"github.com/lucas-clemente/quic-go/http3"
	"github.com/marten-seemann/webtransport-go"
	ma "github.com/multiformats/go-multiaddr"
	manet "github.com/multiformats/go-multiaddr/net"
)

var errClosed = errors.New("closed")

const queueLen = 16
const handshakeTimeout = 10 * time.Second

type listener struct {
	transport   tpt.Transport
	noise       *noise.Transport
	certManager *certManager

	server webtransport.Server

	ctx       context.Context
	ctxCancel context.CancelFunc

	serverClosed chan struct{} // is closed when server.Serve returns

	addr      net.Addr
	multiaddr ma.Multiaddr

	queue chan *webtransport.Conn
}

var _ tpt.Listener = &listener{}

func newListener(laddr ma.Multiaddr, transport tpt.Transport, noise *noise.Transport, certManager *certManager) (tpt.Listener, error) {
	network, addr, err := manet.DialArgs(laddr)
	if err != nil {
		return nil, err
	}
	udpAddr, err := net.ResolveUDPAddr(network, addr)
	if err != nil {
		return nil, err
	}
	udpConn, err := net.ListenUDP(network, udpAddr)
	if err != nil {
		return nil, err
	}
	localMultiaddr, err := toWebtransportMultiaddr(udpConn.LocalAddr())
	if err != nil {
		return nil, err
	}
	ln := &listener{
		transport:    transport,
		noise:        noise,
		certManager:  certManager,
		queue:        make(chan *webtransport.Conn, queueLen),
		serverClosed: make(chan struct{}),
		addr:         udpConn.LocalAddr(),
		multiaddr:    localMultiaddr,
		server: webtransport.Server{
			H3: http3.Server{
				TLSConfig: &tls.Config{GetConfigForClient: func(*tls.ClientHelloInfo) (*tls.Config, error) {
					return certManager.GetConfig(), nil
				}},
			},
		},
	}
	ln.ctx, ln.ctxCancel = context.WithCancel(context.Background())
	mux := http.NewServeMux()
	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Hello, world!"))
	})
	mux.HandleFunc(webtransportHTTPEndpoint, func(w http.ResponseWriter, r *http.Request) {
		// TODO: check ?type=multistream URL param
		c, err := ln.server.Upgrade(w, r)
		if err != nil {
			w.WriteHeader(500)
			return
		}
		// TODO: handle queue overflow
		ln.queue <- c
		// We need to block until we're done with this WebTransport session.
		<-c.Context().Done()
	})
	ln.server.H3.Handler = mux
	go func() {
		defer close(ln.serverClosed)
		defer func() { udpConn.Close() }()
		if err := ln.server.Serve(udpConn); err != nil {
			// TODO: only output if the server hasn't been closed
			log.Debugw("serving failed", "addr", udpConn.LocalAddr(), "error", err)
		}
	}()
	return ln, nil
}

func (l *listener) Accept() (tpt.CapableConn, error) {
	queue := make(chan tpt.CapableConn, queueLen)
	for {
		select {
		case <-l.ctx.Done():
			return nil, errClosed
		default:
		}

		var c *webtransport.Conn
		select {
		case c = <-l.queue:
			go func(c *webtransport.Conn) {
				ctx, cancel := context.WithTimeout(l.ctx, handshakeTimeout)
				defer cancel()
				conn, err := l.handshake(ctx, c)
				if err != nil {
					log.Debugw("handshake failed", "error", err)
					c.Close()
					return
				}
				// TODO: handle queue overflow
				queue <- conn
			}(c)
		case conn := <-queue:
			return conn, nil
		case <-l.ctx.Done():
			return nil, errClosed
		}
	}
}

func (l *listener) handshake(ctx context.Context, c *webtransport.Conn) (tpt.CapableConn, error) {
	str, err := c.AcceptStream(ctx)
	if err != nil {
		return nil, err
	}
	conn, err := l.noise.SecureInbound(ctx, &webtransportStream{Stream: str, wconn: c}, "")
	if err != nil {
		return nil, err
	}
	return newConn(l.transport, c, conn.LocalPrivateKey(), conn.RemotePublicKey())
}

func (l *listener) Addr() net.Addr {
	return l.addr
}

func (l *listener) Multiaddr() ma.Multiaddr {
	return l.multiaddr.Encapsulate(l.certManager.AddrComponent())
}

func (l *listener) Close() error {
	l.ctxCancel()
	err := l.server.Close()
	<-l.serverClosed
	return err
}
<|endoftext|>


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

package generator

import (
	"bufio"
	"fmt"
	"go/parser"
	"go/token"
	"io"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/corsc/go-commons/iocloser"
	"github.com/corsc/go-tools/package-coverage/utils"
)

const coverageFilename = "profile.cov"

var fakeTestFilename = "fake_test.go"

func processAllDirs(basePath string, exclusionsMatcher *regexp.Regexp, logTag string, actionFunc func(string)) {
	paths, err := utils.FindAllGoDirs(basePath)
	if err != nil {
		return
	}

	for _, path := range paths {
		if exclusionsMatcher.FindString(path) != "" {
			utils.LogWhenVerbose("[%s] path '%s' skipped due to skipDir regex '%s'",
				logTag, path, exclusionsMatcher.String())
			continue
		}

		utils.LogWhenVerbose("[%s] processing path '%s'", logTag, path)
		actionFunc(path)
	}
}

// this function will generate the test coverage for the supplied directory
func generateCoverage(path string, exclusions *regexp.Regexp, quietMode bool, tags string) {
	packageName := findPackageName(path)

	fakeTestFile := addFakeTest(path, packageName)
	defer removeFakeTest(fakeTestFile)

	err := execCoverage(path, quietMode, tags)
	if err != nil {
		utils.LogWhenVerbose("[coverage] error generating coverage %s", err)
	}

	if exclusions == nil {
		return
	}

	err = filterCoverage(filepath.Join(path, coverageFilename), exclusions)
	if err != nil {
		utils.LogWhenVerbose("[coverage] error filtering files: %s", err)
	}
}

// add a fake test to ensure that there is at least 1 test in this directory
func addFakeTest(path string, packageName string) string {
	testFilename := createTestFilename(path)

	createTestFile(packageName, testFilename)

	return testFilename
}

func createTestFilename(path string) string {
	return path + fakeTestFilename
}

// find the package name by using the go AST
func findPackageName(path string) string {
	fileSet := token.NewFileSet()
	pkgs, err := parser.ParseDir(fileSet, path, nil, 0)
	if err != nil {
		utils.LogWhenVerbose("[coverage] err while parsing the '%s' into Go AST Err: '%s", path, err)
		return UnknownPackage
	}

	for pkgName := range pkgs {
		return pkgName
	}
	return UnknownPackage
}

// create a fake test so that all directories are guaranteed to contain tests (and therefore coverage will be generated)
func createTestFile(packageName string, testFilename string) {
	utils.LogWhenVerbose("[coverage] created test for package %s file @ %s", packageName, testFilename)

	if _, err := os.Stat(testFilename); err == nil {
		utils.LogWhenVerbose("[coverage] file already exists @ %s cowardly refusing to overwrite", testFilename)
		return
	}

	file, err := os.OpenFile(testFilename, os.O_RDWR|os.O_CREATE, 0600)
	if err != nil {
		utils.LogWhenVerbose("[coverage] error while creating test file %s", err)
		return
	}

	_, err = file.WriteString(`package ` + packageName + `

import "testing"

func TestThisTestDoesntReallyTestAnything(t *testing.T) {}
`)
	if err != nil {
		utils.LogWhenVerbose("[coverage] error while writing test file %s", err)
		return
	}

	err = file.Close()
	if err != nil {
		utils.LogWhenVerbose("[coverage] error while closing file '%s", err)
	}
}

// remove the previously added fake test (i.e. clean up)
func removeFakeTest(filename string) {
	utils.LogWhenVerbose("[coverage] remove test file @ %s", filename)

	err := os.Remove(filename)
	if err != nil {
		utils.LogWhenVerbose("[coverage] error while removing test file @ %s, err: %s", filename, err)
	}
}

// essentially call `go test` to generate the coverage
func execCoverage(dir string, quiet bool, tags string) error {
	arguments := []string{
		"test",
		"-coverprofile=" + coverageFilename,
	}

	if len(tags) > 0 {
		arguments = append(arguments, `-tags="`+tags+`"`)
	}

	cmd := exec.Command("go", arguments...)
	cmd.Dir = dir

	if !quiet {
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
	}

	err := cmd.Run()

	payload, _ := cmd.CombinedOutput()
	utils.LogWhenVerbose("[coverage] test output:\n%s", payload)

	if err != nil {
		utils.LogWhenVerbose("[coverage] error while running go test. err: %s", err)
		return err
	}

	utils.LogWhenVerbose("[coverage] created coverage file @ %s%s", dir, coverageFilename)
	return nil
}

func filterCoverage(coverageFilename string, exclusionsMatcher *regexp.Regexp) error {
	coverageTempFilename := coverageFilename + "~"

	coverageTempFile, err := os.OpenFile(coverageTempFilename, os.O_RDWR|os.O_CREATE, 0600)
	if err != nil {
		utils.LogWhenVerbose("[coverage] error while opening file %s, err: %s", coverageTempFilename, err)
		return err
	}

	defer iocloser.Close(coverageTempFile)

	coverageFile, err := os.OpenFile(coverageFilename, os.O_RDWR, 0)
	if err != nil {
		utils.LogWhenVerbose("[coverage] error while opening file %s, err: %s", coverageFilename, err)
		return err
	}

	defer func() {
		if err := coverageFile.Close(); err != nil {
			utils.LogWhenVerbose("[coverage] Cannot close coverage file %s: %s", coverageFilename, err)
		}
	}()

	if err := filterCoverageContents(exclusionsMatcher, coverageFile, coverageTempFile); err != nil {
		utils.LogWhenVerbose("[coverage] error while filtering coverage file %s: %s", coverageFilename, err)
		return err
	}

	if err := os.Remove(coverageFilename); err != nil {
		utils.LogWhenVerbose("[coverage] cannot remove old coverage file %s: %s", coverageFilename, err)
	}

	if err := os.Rename(coverageTempFilename, coverageFilename); err != nil {
		utils.LogWhenVerbose("[coverage] cannot rename filtered coverage file %s: %s", coverageTempFilename, err)
	}

	return nil
}

func filterCoverageContents(exclusionsMatcher *regexp.Regexp, in io.Reader, out io.Writer) error {
	coverageFileScanner := bufio.NewScanner(in)
	for coverageFileScanner.Scan() {
		line := coverageFileScanner.Text()

		fileNameEndIndex := strings.LastIndex(line, ":")
		if fileNameEndIndex == -1 {
			utils.LogWhenVerbose("[coverage] error in line '%s'", line)
			continue
		}

		fileName := line[:fileNameEndIndex]

		if exclusionsMatcher.MatchString(fileName) {
			utils.LogWhenVerbose("[coverage] skipped file %s", fileName)
			continue
		}

		if _, err := fmt.Fprintln(out, line); err != nil {
			return err
		}
	}

	return nil
}
<commit_msg>Turn on Go modules and add more debugging to test failures<commit_after>// Copyright 2017 Corey Scott http://www.sage42.org/
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package generator

import (
	"bufio"
	"fmt"
	"go/parser"
	"go/token"
	"io"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/corsc/go-commons/iocloser"
	"github.com/corsc/go-tools/package-coverage/utils"
)

const coverageFilename = "profile.cov"

var fakeTestFilename = "fake_test.go"

func processAllDirs(basePath string, exclusionsMatcher *regexp.Regexp, logTag string, actionFunc func(string)) {
	paths, err := utils.FindAllGoDirs(basePath)
	if err != nil {
		return
	}

	for _, path := range paths {
		if exclusionsMatcher.FindString(path) != "" {
			utils.LogWhenVerbose("[%s] path '%s' skipped due to skipDir regex '%s'",
				logTag, path, exclusionsMatcher.String())
			continue
		}

		utils.LogWhenVerbose("[%s] processing path '%s'", logTag, path)
		actionFunc(path)
	}
}

// this function will generate the test coverage for the supplied directory
func generateCoverage(path string, exclusions *regexp.Regexp, quietMode bool, tags string) {
	packageName := findPackageName(path)

	fakeTestFile := addFakeTest(path, packageName)
	defer removeFakeTest(fakeTestFile)

	err := execCoverage(path, quietMode, tags)
	if err != nil {
		utils.LogWhenVerbose("[coverage] error generating coverage %s", err)
	}

	if exclusions == nil {
		return
	}

	err = filterCoverage(filepath.Join(path, coverageFilename), exclusions)
	if err != nil {
		utils.LogWhenVerbose("[coverage] error filtering files: %s", err)
	}
}

// add a fake test to ensure that there is at least 1 test in this directory
func addFakeTest(path string, packageName string) string {
	testFilename := createTestFilename(path)

	createTestFile(packageName, testFilename)

	return testFilename
}

func createTestFilename(path string) string {
	return path + fakeTestFilename
}

// find the package name by using the go AST
func findPackageName(path string) string {
	fileSet := token.NewFileSet()
	pkgs, err := parser.ParseDir(fileSet, path, nil, 0)
	if err != nil {
		utils.LogWhenVerbose("[coverage] err while parsing the '%s' into Go AST Err: '%s", path, err)
		return UnknownPackage
	}

	for pkgName := range pkgs {
		return pkgName
	}
	return UnknownPackage
}

// create a fake test so that all directories are guaranteed to contain tests (and therefore coverage will be generated)
func createTestFile(packageName string, testFilename string) {
	utils.LogWhenVerbose("[coverage] created test for package %s file @ %s", packageName, testFilename)

	if _, err := os.Stat(testFilename); err == nil {
		utils.LogWhenVerbose("[coverage] file already exists @ %s cowardly refusing to overwrite", testFilename)
		return
	}

	file, err := os.OpenFile(testFilename, os.O_RDWR|os.O_CREATE, 0600)
	if err != nil {
		utils.LogWhenVerbose("[coverage] error while creating test file %s", err)
		return
	}

	_, err = file.WriteString(`package ` + packageName + `

import "testing"

func TestThisTestDoesntReallyTestAnything(t *testing.T) {}
`)
	if err != nil {
		utils.LogWhenVerbose("[coverage] error while writing test file %s", err)
		return
	}

	err = file.Close()
	if err != nil {
		utils.LogWhenVerbose("[coverage] error while closing file '%s", err)
	}
}

// remove the previously added fake test (i.e. clean up)
func removeFakeTest(filename string) {
	utils.LogWhenVerbose("[coverage] remove test file @ %s", filename)

	err := os.Remove(filename)
	if err != nil {
		utils.LogWhenVerbose("[coverage] error while removing test file @ %s, err: %s", filename, err)
	}
}

// essentially call `go test` to generate the coverage
func execCoverage(dir string, quiet bool, tags string) error {
	arguments := []string{
		"test",
		"-coverprofile=" + coverageFilename,
	}

	if len(tags) > 0 {
		arguments = append(arguments, `-tags="`+tags+`"`)
	}

	cmd := exec.Command("go", arguments...)
	cmd.Dir = dir

	if !quiet {
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
	}

	err := cmd.Run()

	payload, _ := cmd.CombinedOutput()
	utils.LogWhenVerbose("[coverage] test output %s:\n%s", dir, payload)

	if err != nil {
		utils.LogWhenVerbose("[coverage] error while running go test %s. err: %s", dir, err)
		return err
	}

	utils.LogWhenVerbose("[coverage] created coverage file @ %s%s", dir, coverageFilename)
	return nil
}

func filterCoverage(coverageFilename string, exclusionsMatcher *regexp.Regexp) error {
	coverageTempFilename := coverageFilename + "~"

	coverageTempFile, err := os.OpenFile(coverageTempFilename, os.O_RDWR|os.O_CREATE, 0600)
	if err != nil {
		utils.LogWhenVerbose("[coverage] error while opening file %s, err: %s", coverageTempFilename, err)
		return err
	}

	defer iocloser.Close(coverageTempFile)

	coverageFile, err := os.OpenFile(coverageFilename, os.O_RDWR, 0)
	if err != nil {
		utils.LogWhenVerbose("[coverage] error while opening file %s, err: %s", coverageFilename, err)
		return err
	}

	defer func() {
		if err := coverageFile.Close(); err != nil {
			utils.LogWhenVerbose("[coverage] Cannot close coverage file %s: %s", coverageFilename, err)
		}
	}()

	if err := filterCoverageContents(exclusionsMatcher, coverageFile, coverageTempFile); err != nil {
		utils.LogWhenVerbose("[coverage] error while filtering coverage file %s: %s", coverageFilename, err)
		return err
	}

	if err := os.Remove(coverageFilename); err != nil {
		utils.LogWhenVerbose("[coverage] cannot remove old coverage file %s: %s", coverageFilename, err)
	}

	if err := os.Rename(coverageTempFilename, coverageFilename); err != nil {
		utils.LogWhenVerbose("[coverage] cannot rename filtered coverage file %s: %s", coverageTempFilename, err)
	}

	return nil
}

func filterCoverageContents(exclusionsMatcher *regexp.Regexp, in io.Reader, out io.Writer) error {
	coverageFileScanner := bufio.NewScanner(in)
	for coverageFileScanner.Scan() {
		line := coverageFileScanner.Text()

		fileNameEndIndex := strings.LastIndex(line, ":")
		if fileNameEndIndex == -1 {
			utils.LogWhenVerbose("[coverage] error in line '%s'", line)
			continue
		}

		fileName := line[:fileNameEndIndex]

		if exclusionsMatcher.MatchString(fileName) {
			utils.LogWhenVerbose("[coverage] skipped file %s", fileName)
			continue
		}

		if _, err := fmt.Fprintln(out, line); err != nil {
			return err
		}
	}

	return nil
}
<|endoftext|>


<commit_before>//Copyright 2014 Rana Ian. All rights reserved.
//Use of this source code is governed by The MIT License
//found in the accompanying LICENSE file.

package ora_test

import (
	"fmt"
	"strings"
	"testing"

	"gopkg.in/rana/ora.v4"
)

var _T_stringGen = map[string](func() interface{}){
	"string48":        func() interface{} { return gen_string48() },
	"OraString48":     func() interface{} { return gen_OraString48(false) },
	"OraString48Null": func() interface{} { return gen_OraString48(true) },
}

var _T_stringCols = []string{
	"charB48", "charB48Null",
	"charC48", "charC48Null",
	"nchar48", "nchar48Null",
	"varcharB48", "varcharB48Null",
	"varcharC48", "varcharC48Null",
	"varchar2B48", "varchar2B48Null",
	"varchar2C48", "varchar2C48Null",
	"nvarchar248", "nvarchar248Null",
}

func TestBindDefine_string(t *testing.T) {
	sc := ora.NewStmtCfg()
	for _, ctName := range _T_stringCols {
		for valName, gen := range _T_stringGen {
			t.Run(fmt.Sprintf("%s_%s", valName, ctName), func(t *testing.T) {
				t.Parallel()
				testBindDefine(gen(), _T_colType[ctName], t, sc)
			})
		}
	}
}

func TestBindSlice_string(t *testing.T) {
	sc := ora.NewStmtCfg()
	for valName, gen := range map[string](func() interface{}){
		"stringSlice48":        func() interface{} { return gen_stringSlice48() },
		"OraStringSlice48":     func() interface{} { return gen_OraStringSlice48(false) },
		"OraStringSlice48Null": func() interface{} { return gen_OraStringSlice48(true) },
	} {
		for _, ctName := range _T_stringCols {
			t.Run(fmt.Sprintf("%s_%s", valName, ctName), func(t *testing.T) {
				t.Parallel()
				testBindDefine(gen(), _T_colType[ctName], t, sc)
			})
		}
	}
}

func TestMultiDefine_string(t *testing.T) {
	for _, ctName := range _T_stringCols {
		t.Run(ctName, func(t *testing.T) {
			t.Parallel()
			testMultiDefine(gen_string48(), _T_colType[ctName], t)
		})
	}
}

func TestWorkload_charB48_session(t *testing.T) {
	for _, ctName := range _T_stringCols {
		t.Run(ctName, func(t *testing.T) {
			t.Parallel()
			testWorkload(_T_colType[ctName], t)
		})
	}
}

////////////////////////////////////////////////////////////////////////////////
// long
////////////////////////////////////////////////////////////////////////////////
func TestBindDefine_string_long(t *testing.T) {
	sc := ora.NewStmtCfg()
	for valName, gen := range map[string](func() interface{}){
		"string":             func() interface{} { return gen_string() },
		"stringSlice":        func() interface{} { return gen_stringSlice() },
		"OraString":          func() interface{} { return gen_OraString(false) },
		"OraStringSlice":     func() interface{} { return gen_OraString(false) },
		"OraStringNull":      func() interface{} { return gen_OraString(true) },
		"OraStringSliceNull": func() interface{} { return gen_OraString(true) },
	} {
		for _, ctName := range []string{
			"long", "longNull",
			"clob", "clobNull",
			"nclob", "nclobNull",
		} {
			if strings.HasSuffix(valName, "Null") && !strings.HasSuffix(ctName, "Null") {
				continue
			}
			t.Run(valName+"_"+ctName, func(t *testing.T) {
				if !strings.Contains(ctName, "lob") {
					t.Parallel()
				}
				testBindDefine(gen(), _T_colType[ctName], t, sc)
			})
		}
	}
}

//func TestBindPtr_string_long_session(t *testing.T) {
//	//// ORA-22816: unsupported feature with RETURNING clause
//	//testBindPtr(gen_string(), long, t)
//}

func TestMultiDefine_long_session(t *testing.T) {
	for _, ctName := range []string{
		"long", "longNull",
		"clob", "clobNull",
		"nclob", "nclobNull",
	} {
		t.Run(ctName, func(t *testing.T) {
			t.Parallel()
			testMultiDefine(gen_string(), _T_colType[ctName], t)
		})
	}
}

//func TestWorkload_long_session(t *testing.T) {
//	//// ORA-01754: a table may contain only one column of type LONG
//	//testWorkload(long, t)
//}

//func TestBindPtr_string_longNull_session(t *testing.T) {
//	//// ORA-22816: unsupported feature with RETURNING clause
//	//testBindPtr(gen_string(), longNull, t)
//}

//func TestWorkload_longNull_session(t *testing.T) {
//	//// ORA-01754: a table may contain only one column of type LONG
//	//testWorkload(longNull, t)
//}
<commit_msg>TestStringSlice<commit_after>//Copyright 2014 Rana Ian. All rights reserved.
//Use of this source code is governed by The MIT License
//found in the accompanying LICENSE file.

package ora_test

import (
	"fmt"
	"strings"
	"testing"

	"gopkg.in/rana/ora.v4"
)

var _T_stringGen = map[string](func() interface{}){
	"string48":        func() interface{} { return gen_string48() },
	"OraString48":     func() interface{} { return gen_OraString48(false) },
	"OraString48Null": func() interface{} { return gen_OraString48(true) },
}

var _T_stringCols = []string{
	"charB48", "charB48Null",
	"charC48", "charC48Null",
	"nchar48", "nchar48Null",
	"varcharB48", "varcharB48Null",
	"varcharC48", "varcharC48Null",
	"varchar2B48", "varchar2B48Null",
	"varchar2C48", "varchar2C48Null",
	"nvarchar248", "nvarchar248Null",
}

func TestBindDefine_string(t *testing.T) {
	sc := ora.NewStmtCfg()
	for _, ctName := range _T_stringCols {
		for valName, gen := range _T_stringGen {
			t.Run(fmt.Sprintf("%s_%s", valName, ctName), func(t *testing.T) {
				t.Parallel()
				testBindDefine(gen(), _T_colType[ctName], t, sc)
			})
		}
	}
}

func TestBindSlice_string(t *testing.T) {
	sc := ora.NewStmtCfg()
	for valName, gen := range map[string](func() interface{}){
		"stringSlice48":        func() interface{} { return gen_stringSlice48() },
		"OraStringSlice48":     func() interface{} { return gen_OraStringSlice48(false) },
		"OraStringSlice48Null": func() interface{} { return gen_OraStringSlice48(true) },
	} {
		for _, ctName := range _T_stringCols {
			t.Run(fmt.Sprintf("%s_%s", valName, ctName), func(t *testing.T) {
				t.Parallel()
				testBindDefine(gen(), _T_colType[ctName], t, sc)
			})
		}
	}
}

func TestMultiDefine_string(t *testing.T) {
	for _, ctName := range _T_stringCols {
		t.Run(ctName, func(t *testing.T) {
			t.Parallel()
			testMultiDefine(gen_string48(), _T_colType[ctName], t)
		})
	}
}

func TestWorkload_charB48_session(t *testing.T) {
	for _, ctName := range _T_stringCols {
		t.Run(ctName, func(t *testing.T) {
			t.Parallel()
			testWorkload(_T_colType[ctName], t)
		})
	}
}

////////////////////////////////////////////////////////////////////////////////
// long
////////////////////////////////////////////////////////////////////////////////
func TestBindDefine_string_long(t *testing.T) {
	sc := ora.NewStmtCfg()
	for valName, gen := range map[string](func() interface{}){
		"string":             func() interface{} { return gen_string() },
		"stringSlice":        func() interface{} { return gen_stringSlice() },
		"OraString":          func() interface{} { return gen_OraString(false) },
		"OraStringSlice":     func() interface{} { return gen_OraString(false) },
		"OraStringNull":      func() interface{} { return gen_OraString(true) },
		"OraStringSliceNull": func() interface{} { return gen_OraString(true) },
	} {
		for _, ctName := range []string{
			"long", "longNull",
			"clob", "clobNull",
			"nclob", "nclobNull",
		} {
			if strings.HasSuffix(valName, "Null") && !strings.HasSuffix(ctName, "Null") {
				continue
			}
			t.Run(valName+"_"+ctName, func(t *testing.T) {
				if !strings.Contains(ctName, "lob") {
					t.Parallel()
				}
				testBindDefine(gen(), _T_colType[ctName], t, sc)
			})
		}
	}
}

//func TestBindPtr_string_long_session(t *testing.T) {
//	//// ORA-22816: unsupported feature with RETURNING clause
//	//testBindPtr(gen_string(), long, t)
//}

func TestMultiDefine_long_session(t *testing.T) {
	for _, ctName := range []string{
		"long", "longNull",
		"clob", "clobNull",
		"nclob", "nclobNull",
	} {
		t.Run(ctName, func(t *testing.T) {
			t.Parallel()
			testMultiDefine(gen_string(), _T_colType[ctName], t)
		})
	}
}

//func TestWorkload_long_session(t *testing.T) {
//	//// ORA-01754: a table may contain only one column of type LONG
//	//testWorkload(long, t)
//}

//func TestBindPtr_string_longNull_session(t *testing.T) {
//	//// ORA-22816: unsupported feature with RETURNING clause
//	//testBindPtr(gen_string(), longNull, t)
//}

//func TestWorkload_longNull_session(t *testing.T) {
//	//// ORA-01754: a table may contain only one column of type LONG
//	//testWorkload(longNull, t)
//}

func TestStringSlice(t *testing.T) {
	for _, nls_param := range []string{
		//`NLS_LANGUAGE = 'hungarian_hungary.ee9iso8859p2'`,
		`NLS_DATE_FORMAT = 'YYYY-MM-DD"T"HH24:MI:SS'`,
		`NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS.FF'`,
		`NLS_NUMERIC_CHARACTERS = '.,'`,
	} {
		qry := "ALTER SESSION SET " + nls_param
		if _, err := testSes.PrepAndExe(qry); err != nil {
			t.Fatal(qry, err)
		}
	}
	tbl := tableName()
	qry := "CREATE TABLE " + tbl + ` (
  "BUC_BUG_ID" NUMBER(9,0),
  "BUC_NUMMER" NUMBER(7,0),
  "BUC_DEBITOR_KREDITOR_KENNZ" VARCHAR2(38),
  "BUC_SACHKONTENGRUPPE" VARCHAR2(32),
  "BUC_SKT_CODE" VARCHAR2(25),
  "BUC_KTK_CODE" VARCHAR2(25),
  "BUC_WAE_CODE" VARCHAR2(25),
  "BUC_BETRAG" NUMBER(15,2),
  "BUC_STEUERSCHLUESSEL" VARCHAR2(32),
  "BUC_ZAHLUNGSZIEL" DATE,
  "BUC_TYP" VARCHAR2(19),
  "BUC_MANDANT_PAR_NUMMER" NUMBER(11,0),
  "BUC_MANDANT_PAD_CODE" VARCHAR2(32),
  "BUC_MANDANT_FIBU_KONTONR" NUMBER(16,0),
  "BUC_PARTNER_PAD_CODE" VARCHAR2(32),
  "BUC_PARTNER_NUMMER" NUMBER(11,0),
  "BUC_PARTNER_FIBU_KONTONR" NUMBER(16,0),
  "BUC_VER_NUMMER" NUMBER(11,0),
  "BUC_VVS_NUMMER" NUMBER(9,0),
  "BUC_DEC_NUMMER" NUMBER(9,0),
  "BUC_PRD_NUMMER" VARCHAR2(27),
  "BUC_PBS_NUMMER" NUMBER(9,0),
  "BUC_OBJ_ID" NUMBER(9,0),
  "BUC_OBJ_NUMMER" NUMBER(9,0),
  "BUC_PARTNER_KONTONUMMER" VARCHAR2(36),
  "BUC_PARTNER_BANKLEITZAHL" VARCHAR2(37),
  "BUC_TEXT" VARCHAR2(74),
  "BUC_ERSTELLT_VON" VARCHAR2(29),
  "BUC_ERSTELLUNGSZEITPUNKT" DATE,
  "BUC_GEAENDERT_VON" VARCHAR2(30),
  "BUC_AENDERUNGSZEITPUNKT" DATE,
  "BUC_DPR_ID" NUMBER(9,0),
  "BUC_BETRAG_HW" NUMBER(15,2),
  "BUC_PBT_ID" NUMBER(9,0),
  "BUC_PARTNER_BANKKONTOINHABER" NUMBER(11,0),
  "BUC_PVN_ID" NUMBER(9,0),
  "BUC_KTO_LFDNUMMER" NUMBER(9,0),
  "BUC_BTP_ID" NUMBER(9,0),
  "BUC_MAKLER_ABRECHNUNGS_KNZ" VARCHAR2(38),
  "BUC_SWIFTCODE" VARCHAR2(26),
  "BUC_BANKNAME" VARCHAR2(25),
  "BUC_BANKORT" VARCHAR2(24),
  "BUC_IBAN" VARCHAR2(21),
  "BUC_RV_VERTRAGSNUMMER" NUMBER(12,0),
  "BUC_RV_VERTRAGSVERSION" NUMBER(10,0),
  "BUC_RV_VERTRAGSART" NUMBER(2,0),
  "BUC_HTV_CODE" VARCHAR2(25),
  "BUC_BELEGART_NB" VARCHAR2(27),
  "BUC_VSV_EXTERNER_CODE" VARCHAR2(33),
  "BUC_ORG_NUMMER_VEAB" VARCHAR2(32),
  "BUC_ORG_NUMMER_VTVZ" VARCHAR2(32),
  "BUC_KOSTENSTELLE_VM" VARCHAR2(32),
  "BUC_KIRCHENSTEUERSATZ" NUMBER(5,2),
  "BUC_RELIGIONSGEMEINSCHAFT" VARCHAR2(38)
  , "BUC_COC_SPERR_ID" RAW(16)
  , "BUC_COC_LOESCH_ID" RAW(16)
  )`
	if _, err := testSes.PrepAndExe(qry); err != nil {
		t.Fatal(qry, err)
	}
	defer testSes.PrepAndExe("DROP TABLE " + tbl)
	qry = "INSERT INTO " + tbl + `
	("BUC_BUG_ID", "BUC_NUMMER", "BUC_DEBITOR_KREDITOR_KENNZ", "BUC_SACHKONTENGRUPPE", "BUC_SKT_CODE", "BUC_KTK_CODE", "BUC_WAE_CODE", "BUC_BETRAG", "BUC_STEUERSCHLUESSEL", "BUC_ZAHLUNGSZIEL", "BUC_TYP", "BUC_MANDANT_PAR_NUMMER", "BUC_MANDANT_PAD_CODE", "BUC_MANDANT_FIBU_KONTONR", "BUC_PARTNER_PAD_CODE", "BUC_PARTNER_NUMMER", "BUC_PARTNER_FIBU_KONTONR", "BUC_VER_NUMMER", "BUC_VVS_NUMMER", "BUC_DEC_NUMMER", "BUC_PRD_NUMMER", "BUC_PBS_NUMMER", "BUC_OBJ_ID", "BUC_OBJ_NUMMER", "BUC_PARTNER_KONTONUMMER", "BUC_PARTNER_BANKLEITZAHL", "BUC_TEXT", "BUC_ERSTELLT_VON", "BUC_ERSTELLUNGSZEITPUNKT", "BUC_GEAENDERT_VON", "BUC_AENDERUNGSZEITPUNKT", "BUC_DPR_ID", "BUC_BETRAG_HW", "BUC_PBT_ID", "BUC_PARTNER_BANKKONTOINHABER", "BUC_PVN_ID", "BUC_KTO_LFDNUMMER", "BUC_BTP_ID", "BUC_MAKLER_ABRECHNUNGS_KNZ", "BUC_SWIFTCODE", "BUC_BANKNAME", "BUC_BANKORT", "BUC_IBAN", "BUC_RV_VERTRAGSNUMMER", "BUC_RV_VERTRAGSVERSION", "BUC_RV_VERTRAGSART", "BUC_HTV_CODE", "BUC_BELEGART_NB", "BUC_VSV_EXTERNER_CODE", "BUC_ORG_NUMMER_VEAB", "BUC_ORG_NUMMER_VTVZ", "BUC_KOSTENSTELLE_VM", "BUC_KIRCHENSTEUERSATZ", "BUC_RELIGIONSGEMEINSCHAFT", "BUC_COC_SPERR_ID", "BUC_COC_LOESCH_ID")
	VALUES
	(
	:1, :2, :3, :4, :5, :6, :7, :8, :9, :10, :11, :12, :13, :14, :15, :16, :17, :18, :19, :20, :21, :22, :23, :24, :25, :26, :27, :28, :29, :30, :31, :32, :33, :34, :35, :36, :37, :38, :39, :40, :41, :42, :43, :44, :45, :46, :47, :48, :49, :50, :51, :52, :53, :54
	, :55, :56
	)`
	stmt, err := testSes.Prep(qry)
	if err != nil {
		t.Fatal(qry, err)
	}
	defer stmt.Close()

	params := []interface{}{
		[]string{"3979", "3979"}, []string{"5", "6"}, []string{"D", "D"}, []string{"03", "03"}, []string{"429999", "429999"}, []string{"P10DLP000000901", "P10DLP000000901"}, []string{"HUF", "HUF"}, []string{"215.00", "171.00"}, []string{"S0", "S0"}, []string{"2007-11-12T00:00:00", "2007-11-12T00:00:00"}, []string{"F", "F"}, []string{"1", "1"}, []string{"MAN", "MAN"}, []string{"0", "0"}, []string{"VN", "VN"}, []string{"870009593", "870009593"}, []string{"870009593", "870009593"}, []string{"90000044121", "90000044132"}, []string{"1", "1"}, []string{"2", "1"}, []string{"01", "03"}, []string{"2", "1"}, []string{"5680656", "0"}, []string{"1", "0"}, []string{"1034827949010019", "1034827949010019"}, []string{"10300002", "10300002"}, []string{"háztartási vagyonrész betöréses lopás", "Magánszemélyek felelősségbiztosítása"}, []string{"BARCSAI", "BARCSAI"}, []string{"2007-11-12T13:04:22", "2007-11-12T13:04:25"}, []string{"", ""}, []string{"", ""}, []string{"6718", "6719"}, []string{"215.00", "171.00"}, []string{"0", "0"}, []string{"870009593", "870009593"}, []string{"0", "0"}, []string{"1", "1"}, []string{"0", "0"}, []string{"", ""}, []string{"", ""}, []string{"", ""}, []string{"", ""}, []string{"", ""}, []string{"0", "0"}, []string{"0", "0"}, []string{"0", "0"}, []string{"A110A110", "A110A110"}, []string{"11", "11"}, []string{"Z0", "Z0"}, []string{"", ""}, []string{"", ""}, []string{"", ""}, []string{"0", "0"}, []string{"", ""},
		[][]uint8{[]uint8(nil), []uint8(nil)}, [][]uint8{[]uint8(nil), []uint8(nil)},
	}

	for i := 0; i < 10; i++ {
		t.Logf("%d.", i)
		if _, err := stmt.Exe(params...); err != nil {
			t.Fatal(i, err)
		}
	}

	qry = "SELECT COUNT(0) FROM " + tbl
	rset, err := testSes.PrepAndQry(qry)
	if err != nil {
		t.Fatal(qry, err)
	}
	rset.Next()
	t.Log(rset.Row[0])

}
<|endoftext|>


<commit_before>package uploadedfile

import (
	"errors"
	"fmt"
	"math"
	"os"
	"regexp"
	"strconv"

	"github.com/Imgur/mandible/imageprocessor/processorcommand"
	"github.com/Imgur/mandible/imageprocessor/thumbType"
)

var (
	defaultQuality   = 83
	maxImageSideSize = 10000
)

type ThumbFile struct {
	localPath string

	Name          string
	Width         int
	MaxWidth      int
	Height        int
	MaxHeight     int
	Shape         string
	CropGravity   string
	CropWidth     int
	CropHeight    int
	CropRatio     string
	Quality       int
	Format        string
	StoreURI      string
	DesiredFormat string
}

func NewThumbFile(width, maxWidth, height, maxHeight int, name, shape, path, cropGravity string, cropWidth, cropHeight int, cropRatio string, quality int, desiredFormat string) *ThumbFile {
	if quality == 0 {
		quality = defaultQuality
	}

	return &ThumbFile{
		localPath: path,

		Name:          name,
		Width:         width,
		MaxWidth:      maxWidth,
		Height:        height,
		MaxHeight:     maxHeight,
		Shape:         shape,
		CropGravity:   cropGravity,
		CropWidth:     cropWidth,
		CropHeight:    cropHeight,
		CropRatio:     cropRatio,
		Quality:       quality,
		Format:        "",
		StoreURI:      "",
		DesiredFormat: desiredFormat,
	}
}

func (this *ThumbFile) SetPath(path string) error {
	if _, err := os.Stat(path); os.IsNotExist(err) {
		return errors.New(fmt.Sprintf("Error when creating thumbnail %s", this.Name))
	}

	this.localPath = path

	return nil
}

func (this *ThumbFile) GetPath() string {
	return this.localPath
}

func (this *ThumbFile) GetOutputFormat(original *UploadedFile) thumbType.ThumbType {
	if this.DesiredFormat != "" {
		return thumbType.FromString(this.DesiredFormat)
	}

	return thumbType.FromMime(original.GetMime())
}

func (this *ThumbFile) ComputeWidth(original *UploadedFile) int {
	width := this.Width

	oWidth, _, err := original.Dimensions()
	if err != nil {
		return 0
	}

	if this.MaxWidth > 0 {
		width = int(math.Min(float64(oWidth), float64(this.MaxWidth)))
	}

	return width
}

func (this *ThumbFile) ComputeHeight(original *UploadedFile) int {
	height := this.Height

	_, oHeight, err := original.Dimensions()
	if err != nil {
		return 0
	}

	if this.MaxHeight > 0 {
		height = int(math.Min(float64(oHeight), float64(this.MaxHeight)))
	}

	return height
}

func (this *ThumbFile) ComputeCrop(original *UploadedFile) (int, int, error) {
	re := regexp.MustCompile("(.*):(.*)")
	matches := re.FindStringSubmatch(this.CropRatio)
	if len(matches) != 3 {
		return 0, 0, errors.New("Invalid crop_ratio")
	}

	wRatio, werr := strconv.ParseFloat(matches[1], 64)
	hRatio, herr := strconv.ParseFloat(matches[2], 64)
	if werr != nil || herr != nil {
		return 0, 0, errors.New("Invalid crop_ratio")
	}

	var cropWidth, cropHeight float64

	if wRatio >= hRatio {
		wRatio = wRatio / hRatio
		hRatio = 1
		cropWidth = math.Ceil(float64(this.ComputeHeight(original)) * wRatio)
		cropHeight = math.Ceil(float64(this.ComputeHeight(original)) * hRatio)
	} else {
		hRatio = hRatio / wRatio
		wRatio = 1
		cropWidth = math.Ceil(float64(this.ComputeWidth(original)) * wRatio)
		cropHeight = math.Ceil(float64(this.ComputeWidth(original)) * hRatio)
	}

	return int(cropWidth), int(cropHeight), nil
}

func (this *ThumbFile) Process(original *UploadedFile) error {
	switch this.Shape {
	case "circle":
		return this.processCircle(original)
	case "thumb":
		return this.processThumb(original)
	case "square":
		return this.processSquare(original)
	case "custom":
		return this.processCustom(original)
	default:
		return this.processFull(original)
	}
}

func (this *ThumbFile) String() string {
	return fmt.Sprintf("Thumbnail of <%s>", this.Name)
}

func (this *ThumbFile) processSquare(original *UploadedFile) error {
	if this.Width == 0 {
		return errors.New("Width cannot be 0")
	}
	if this.Width > maxImageSideSize {
		return errors.New("Width too large")
	}

	filename, err := processorcommand.SquareThumb(original.GetPath(), this.Name, this.Width, this.Quality, this.GetOutputFormat(original))
	if err != nil {
		return err
	}

	if err := this.SetPath(filename); err != nil {
		return err
	}

	return nil
}

func (this *ThumbFile) processCircle(original *UploadedFile) error {
	if this.Width == 0 {
		return errors.New("Width cannot be 0")
	}
	if this.Width > maxImageSideSize {
		return errors.New("Width too large")
	}

	//Circle thumbs should always be PNGs for transparency reasons.
	outputFormat := thumbType.FromString("png")

	filename, err := processorcommand.CircleThumb(original.GetPath(), this.Name, this.Width, this.Quality, outputFormat)
	if err != nil {
		return err
	}

	if err := this.SetPath(filename); err != nil {
		return err
	}

	return nil
}

func (this *ThumbFile) processThumb(original *UploadedFile) error {
	if this.Width == 0 {
		return errors.New("Width cannot be 0")
	}
	if this.Width > maxImageSideSize {
		return errors.New("Width too large")
	}
	if this.Height == 0 {
		return errors.New("Height cannot be 0")
	}
	if this.Height > maxImageSideSize {
		return errors.New("Height too large")
	}

	filename, err := processorcommand.Thumb(original.GetPath(), this.Name, this.Width, this.Height, this.Quality, this.GetOutputFormat(original))
	if err != nil {
		return err
	}

	if err := this.SetPath(filename); err != nil {
		return err
	}

	return nil
}

func (this *ThumbFile) processCustom(original *UploadedFile) error {
	cropWidth := this.CropWidth
	cropHeight := this.CropHeight
	var err error

	if this.CropRatio != "" {
		cropWidth, cropHeight, err = this.ComputeCrop(original)
		if err != nil {
			return err
		}
	}

	width := this.ComputeWidth(original)
	height := this.ComputeHeight(original)
	validWidth := width > 0 && width <= maxImageSideSize
	validHeight := height > 0 && height <= maxImageSideSize

	if !validWidth && !validHeight {
		if !validWidth {
			return errors.New("Invalid width")
		}

		return errors.New("Invalid height")
	}

	filename, err := processorcommand.CustomThumb(original.GetPath(), this.Name, width, height, this.CropGravity, cropWidth, cropHeight, this.Quality, this.GetOutputFormat(original))
	if err != nil {
		return err
	}

	if err := this.SetPath(filename); err != nil {
		return err
	}

	return nil
}

func (this *ThumbFile) processFull(original *UploadedFile) error {
	filename, err := processorcommand.Full(original.GetPath(), this.Name, this.Quality, this.GetOutputFormat(original))
	if err != nil {
		return err
	}

	if err := this.SetPath(filename); err != nil {
		return err
	}

	return nil
}
<commit_msg>Update thumbfile.go<commit_after>package uploadedfile

import (
	"errors"
	"fmt"
	"math"
	"os"
	"regexp"
	"strconv"

	"github.com/Imgur/mandible/imageprocessor/processorcommand"
	"github.com/Imgur/mandible/imageprocessor/thumbType"
)

var (
	defaultQuality   = 83
	maxImageSideSize = 10000
)

type ThumbFile struct {
	localPath string

	Name          string
	Width         int
	MaxWidth      int
	Height        int
	MaxHeight     int
	Shape         string
	CropGravity   string
	CropWidth     int
	CropHeight    int
	CropRatio     string
	Quality       int
	Format        string
	StoreURI      string
	DesiredFormat string
}

func NewThumbFile(width, maxWidth, height, maxHeight int, name, shape, path, cropGravity string, cropWidth, cropHeight int, cropRatio string, quality int, desiredFormat string) *ThumbFile {
	if quality == 0 {
		quality = defaultQuality
	}

	return &ThumbFile{
		localPath: path,

		Name:          name,
		Width:         width,
		MaxWidth:      maxWidth,
		Height:        height,
		MaxHeight:     maxHeight,
		Shape:         shape,
		CropGravity:   cropGravity,
		CropWidth:     cropWidth,
		CropHeight:    cropHeight,
		CropRatio:     cropRatio,
		Quality:       quality,
		Format:        "",
		StoreURI:      "",
		DesiredFormat: desiredFormat,
	}
}

func (this *ThumbFile) SetPath(path string) error {
	if _, err := os.Stat(path); os.IsNotExist(err) {
		return errors.New(fmt.Sprintf("Error when creating thumbnail %s", this.Name))
	}

	this.localPath = path

	return nil
}

func (this *ThumbFile) GetPath() string {
	return this.localPath
}

func (this *ThumbFile) GetOutputFormat(original *UploadedFile) thumbType.ThumbType {
	if this.DesiredFormat != "" {
		return thumbType.FromString(this.DesiredFormat)
	}

	return thumbType.FromMime(original.GetMime())
}

func (this *ThumbFile) ComputeWidth(original *UploadedFile) int {
	width := this.Width

	oWidth, _, err := original.Dimensions()
	if err != nil {
		return 0
	}

	if this.MaxWidth > 0 {
		width = int(math.Min(float64(oWidth), float64(this.MaxWidth)))
	}

	return width
}

func (this *ThumbFile) ComputeHeight(original *UploadedFile) int {
	height := this.Height

	_, oHeight, err := original.Dimensions()
	if err != nil {
		return 0
	}

	if this.MaxHeight > 0 {
		height = int(math.Min(float64(oHeight), float64(this.MaxHeight)))
	}

	return height
}

func (this *ThumbFile) ComputeCrop(original *UploadedFile) (int, int, error) {
	re := regexp.MustCompile("(.*):(.*)")
	matches := re.FindStringSubmatch(this.CropRatio)
	if len(matches) != 3 {
		return 0, 0, errors.New("Invalid crop_ratio")
	}

	wRatio, werr := strconv.ParseFloat(matches[1], 64)
	hRatio, herr := strconv.ParseFloat(matches[2], 64)
	if werr != nil || herr != nil {
		return 0, 0, errors.New("Invalid crop_ratio")
	}

	var cropWidth, cropHeight float64

	if wRatio >= hRatio {
		wRatio = wRatio / hRatio
		hRatio = 1
		cropWidth = math.Ceil(float64(this.ComputeHeight(original)) * wRatio)
		cropHeight = math.Ceil(float64(this.ComputeHeight(original)) * hRatio)
	} else {
		hRatio = hRatio / wRatio
		wRatio = 1
		cropWidth = math.Ceil(float64(this.ComputeWidth(original)) * wRatio)
		cropHeight = math.Ceil(float64(this.ComputeWidth(original)) * hRatio)
	}

	return int(cropWidth), int(cropHeight), nil
}

func (this *ThumbFile) Process(original *UploadedFile) error {
	switch this.Shape {
	case "circle":
		return this.processCircle(original)
	case "thumb":
		return this.processThumb(original)
	case "square":
		return this.processSquare(original)
	case "custom":
		return this.processCustom(original)
	default:
		return this.processFull(original)
	}
}

func (this *ThumbFile) String() string {
	return fmt.Sprintf("Thumbnail of <%s>", this.Name)
}

func (this *ThumbFile) processSquare(original *UploadedFile) error {
	if this.Width == 0 {
		return errors.New("Width cannot be 0")
	}
	if this.Width > maxImageSideSize {
		return errors.New("Width too large")
	}

	filename, err := processorcommand.SquareThumb(original.GetPath(), this.Name, this.Width, this.Quality, this.GetOutputFormat(original))
	if err != nil {
		return err
	}

	if err := this.SetPath(filename); err != nil {
		return err
	}

	return nil
}

func (this *ThumbFile) processCircle(original *UploadedFile) error {
	if this.Width == 0 {
		return errors.New("Width cannot be 0")
	}
	if this.Width > maxImageSideSize {
		return errors.New("Width too large")
	}

	//Circle thumbs should always be PNGs
	outputFormat := thumbType.FromString("png")

	filename, err := processorcommand.CircleThumb(original.GetPath(), this.Name, this.Width, this.Quality, outputFormat)
	if err != nil {
		return err
	}

	if err := this.SetPath(filename); err != nil {
		return err
	}

	return nil
}

func (this *ThumbFile) processThumb(original *UploadedFile) error {
	if this.Width == 0 {
		return errors.New("Width cannot be 0")
	}
	if this.Width > maxImageSideSize {
		return errors.New("Width too large")
	}
	if this.Height == 0 {
		return errors.New("Height cannot be 0")
	}
	if this.Height > maxImageSideSize {
		return errors.New("Height too large")
	}

	filename, err := processorcommand.Thumb(original.GetPath(), this.Name, this.Width, this.Height, this.Quality, this.GetOutputFormat(original))
	if err != nil {
		return err
	}

	if err := this.SetPath(filename); err != nil {
		return err
	}

	return nil
}

func (this *ThumbFile) processCustom(original *UploadedFile) error {
	cropWidth := this.CropWidth
	cropHeight := this.CropHeight
	var err error

	if this.CropRatio != "" {
		cropWidth, cropHeight, err = this.ComputeCrop(original)
		if err != nil {
			return err
		}
	}

	width := this.ComputeWidth(original)
	height := this.ComputeHeight(original)
	validWidth := width > 0 && width <= maxImageSideSize
	validHeight := height > 0 && height <= maxImageSideSize

	if !validWidth && !validHeight {
		if !validWidth {
			return errors.New("Invalid width")
		}

		return errors.New("Invalid height")
	}

	filename, err := processorcommand.CustomThumb(original.GetPath(), this.Name, width, height, this.CropGravity, cropWidth, cropHeight, this.Quality, this.GetOutputFormat(original))
	if err != nil {
		return err
	}

	if err := this.SetPath(filename); err != nil {
		return err
	}

	return nil
}

func (this *ThumbFile) processFull(original *UploadedFile) error {
	filename, err := processorcommand.Full(original.GetPath(), this.Name, this.Quality, this.GetOutputFormat(original))
	if err != nil {
		return err
	}

	if err := this.SetPath(filename); err != nil {
		return err
	}

	return nil
}
<|endoftext|>