<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io"
	"os/exec"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/docker/docker/pkg/integration/checker"
	"github.com/docker/docker/pkg/timeutils"
	"github.com/go-check/check"
)

// This used to work, it test a log of PageSize-1 (gh#4851)
func (s *DockerSuite) TestLogsContainerSmallerThanPage(c *check.C) {
	testRequires(c, DaemonIsLinux)
	testLen := 32767
	out, _ := dockerCmd(c, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("for i in $(seq 1 %d); do echo -n =; done; echo", testLen))

	id := strings.TrimSpace(out)
	dockerCmd(c, "wait", id)

	out, _ = dockerCmd(c, "logs", id)

	c.Assert(out, checker.HasLen, testLen+1)
}

// Regression test: When going over the PageSize, it used to panic (gh#4851)
func (s *DockerSuite) TestLogsContainerBiggerThanPage(c *check.C) {
	testRequires(c, DaemonIsLinux)
	testLen := 32768
	out, _ := dockerCmd(c, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("for i in $(seq 1 %d); do echo -n =; done; echo", testLen))

	id := strings.TrimSpace(out)
	dockerCmd(c, "wait", id)

	out, _ = dockerCmd(c, "logs", id)

	c.Assert(out, checker.HasLen, testLen+1)
}

// Regression test: When going much over the PageSize, it used to block (gh#4851)
func (s *DockerSuite) TestLogsContainerMuchBiggerThanPage(c *check.C) {
	testRequires(c, DaemonIsLinux)
	testLen := 33000
	out, _ := dockerCmd(c, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("for i in $(seq 1 %d); do echo -n =; done; echo", testLen))

	id := strings.TrimSpace(out)
	dockerCmd(c, "wait", id)

	out, _ = dockerCmd(c, "logs", id)

	c.Assert(out, checker.HasLen, testLen+1)
}

func (s *DockerSuite) TestLogsTimestamps(c *check.C) {
	testRequires(c, DaemonIsLinux)
	testLen := 100
	out, _ := dockerCmd(c, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("for i in $(seq 1 %d); do echo =; done;", testLen))

	id := strings.TrimSpace(out)
	dockerCmd(c, "wait", id)

	out, _ = dockerCmd(c, "logs", "-t", id)

	lines := strings.Split(out, "\n")

	c.Assert(lines, checker.HasLen, testLen+1)

	ts := regexp.MustCompile(`^.* `)

	for _, l := range lines {
		if l != "" {
			_, err := time.Parse(timeutils.RFC3339NanoFixed+" ", ts.FindString(l))
			c.Assert(err, checker.IsNil, check.Commentf("Failed to parse timestamp from %v", l))
			// ensure we have padded 0's
			c.Assert(l[29], checker.Equals, uint8('Z'))
		}
	}
}

func (s *DockerSuite) TestLogsSeparateStderr(c *check.C) {
	testRequires(c, DaemonIsLinux)
	msg := "stderr_log"
	out, _ := dockerCmd(c, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("echo %s 1>&2", msg))

	id := strings.TrimSpace(out)
	dockerCmd(c, "wait", id)

	stdout, stderr, _ := dockerCmdWithStdoutStderr(c, "logs", id)

	c.Assert(stdout, checker.Equals, "")

	stderr = strings.TrimSpace(stderr)

	c.Assert(stderr, checker.Equals, msg)
}

func (s *DockerSuite) TestLogsStderrInStdout(c *check.C) {
	testRequires(c, DaemonIsLinux)
	msg := "stderr_log"
	out, _ := dockerCmd(c, "run", "-d", "-t", "busybox", "sh", "-c", fmt.Sprintf("echo %s 1>&2", msg))

	id := strings.TrimSpace(out)
	dockerCmd(c, "wait", id)

	stdout, stderr, _ := dockerCmdWithStdoutStderr(c, "logs", id)
	c.Assert(stderr, checker.Equals, "")

	stdout = strings.TrimSpace(stdout)
	c.Assert(stdout, checker.Equals, msg)
}

func (s *DockerSuite) TestLogsTail(c *check.C) {
	testRequires(c, DaemonIsLinux)
	testLen := 100
	out, _ := dockerCmd(c, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("for i in $(seq 1 %d); do echo =; done;", testLen))

	id := strings.TrimSpace(out)
	dockerCmd(c, "wait", id)

	out, _ = dockerCmd(c, "logs", "--tail", "5", id)

	lines := strings.Split(out, "\n")

	c.Assert(lines, checker.HasLen, 6)

	out, _ = dockerCmd(c, "logs", "--tail", "all", id)

	lines = strings.Split(out, "\n")

	c.Assert(lines, checker.HasLen, testLen+1)

	out, _, _ = dockerCmdWithStdoutStderr(c, "logs", "--tail", "random", id)

	lines = strings.Split(out, "\n")

	c.Assert(lines, checker.HasLen, testLen+1)
}

func (s *DockerSuite) TestLogsFollowStopped(c *check.C) {
	testRequires(c, DaemonIsLinux)
	out, _ := dockerCmd(c, "run", "-d", "busybox", "echo", "hello")

	id := strings.TrimSpace(out)
	dockerCmd(c, "wait", id)

	logsCmd := exec.Command(dockerBinary, "logs", "-f", id)
	c.Assert(logsCmd.Start(), checker.IsNil)

	errChan := make(chan error)
	go func() {
		errChan <- logsCmd.Wait()
		close(errChan)
	}()

	select {
	case err := <-errChan:
		c.Assert(err, checker.IsNil)
	case <-time.After(1 * time.Second):
		c.Fatal("Following logs is hanged")
	}
}

func (s *DockerSuite) TestLogsSince(c *check.C) {
	testRequires(c, DaemonIsLinux)
	name := "testlogssince"
	out, _ := dockerCmd(c, "run", "--name="+name, "busybox", "/bin/sh", "-c", "for i in $(seq 1 3); do sleep 2; echo `date +%s` log$i; done")

	log2Line := strings.Split(strings.Split(out, "\n")[1], " ")
	t, err := strconv.ParseInt(log2Line[0], 10, 64) // the timestamp log2 is written
	c.Assert(err, checker.IsNil)
	since := t + 1 // add 1s so log1 & log2 doesn't show up
	out, _ = dockerCmd(c, "logs", "-t", fmt.Sprintf("--since=%v", since), name)

	// Skip 2 seconds
	unexpected := []string{"log1", "log2"}
	for _, v := range unexpected {
		c.Assert(out, checker.Not(checker.Contains), v, check.Commentf("unexpected log message returned, since=%v", since))
	}

	// Test to make sure a bad since format is caught by the client
	out, _, _ = dockerCmdWithError("logs", "-t", "--since=2006-01-02T15:04:0Z", name)
	c.Assert(out, checker.Contains, "cannot parse \"0Z\" as \"05\"", check.Commentf("bad since format passed to server"))

	// Test with default value specified and parameter omitted
	expected := []string{"log1", "log2", "log3"}
	for _, cmd := range []*exec.Cmd{
		exec.Command(dockerBinary, "logs", "-t", name),
		exec.Command(dockerBinary, "logs", "-t", "--since=0", name),
	} {
		out, _, err = runCommandWithOutput(cmd)
		c.Assert(err, checker.IsNil, check.Commentf("failed to log container: %s", out))
		for _, v := range expected {
			c.Assert(out, checker.Contains, v)
		}
	}
}

func (s *DockerSuite) TestLogsSinceFutureFollow(c *check.C) {
	testRequires(c, DaemonIsLinux)
	out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", `for i in $(seq 1 5); do date +%s; sleep 1; done`)
	id := strings.TrimSpace(out)

	now := daemonTime(c).Unix()
	since := now + 2
	out, _ = dockerCmd(c, "logs", "-f", fmt.Sprintf("--since=%v", since), id)
	lines := strings.Split(strings.TrimSpace(out), "\n")
	c.Assert(lines, checker.Not(checker.HasLen), 0)
	for _, v := range lines {
		ts, err := strconv.ParseInt(v, 10, 64)
		c.Assert(err, checker.IsNil, check.Commentf("cannot parse timestamp output from log: '%v'\nout=%s", v, out))
		c.Assert(ts >= since, checker.Equals, true, check.Commentf("earlier log found. since=%v logdate=%v", since, ts))
	}
}

// Regression test for #8832
func (s *DockerSuite) TestLogsFollowSlowStdoutConsumer(c *check.C) {
	testRequires(c, DaemonIsLinux)
	out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", `usleep 600000;yes X | head -c 200000`)

	id := strings.TrimSpace(out)

	stopSlowRead := make(chan bool)

	go func() {
		exec.Command(dockerBinary, "wait", id).Run()
		stopSlowRead <- true
	}()

	logCmd := exec.Command(dockerBinary, "logs", "-f", id)
	stdout, err := logCmd.StdoutPipe()
	c.Assert(err, checker.IsNil)
	c.Assert(logCmd.Start(), checker.IsNil)

	// First read slowly
	bytes1, err := consumeWithSpeed(stdout, 10, 50*time.Millisecond, stopSlowRead)
	c.Assert(err, checker.IsNil)

	// After the container has finished we can continue reading fast
	bytes2, err := consumeWithSpeed(stdout, 32*1024, 0, nil)
	c.Assert(err, checker.IsNil)

	actual := bytes1 + bytes2
	expected := 200000
	c.Assert(actual, checker.Equals, expected)

}

func (s *DockerSuite) TestLogsFollowGoroutinesWithStdout(c *check.C) {
	testRequires(c, DaemonIsLinux)
	out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "while true; do echo hello; sleep 2; done")
	id := strings.TrimSpace(out)
	c.Assert(waitRun(id), checker.IsNil)

	type info struct {
		NGoroutines int
	}
	getNGoroutines := func() int {
		var i info
		status, b, err := sockRequest("GET", "/info", nil)
		c.Assert(err, checker.IsNil)
		c.Assert(status, checker.Equals, 200)
		c.Assert(json.Unmarshal(b, &i), checker.IsNil)
		return i.NGoroutines
	}

	nroutines := getNGoroutines()

	cmd := exec.Command(dockerBinary, "logs", "-f", id)
	r, w := io.Pipe()
	cmd.Stdout = w
	c.Assert(cmd.Start(), checker.IsNil)

	// Make sure pipe is written to
	chErr := make(chan error)
	go func() {
		b := make([]byte, 1)
		_, err := r.Read(b)
		chErr <- err
	}()
	c.Assert(<-chErr, checker.IsNil)
	c.Assert(cmd.Process.Kill(), checker.IsNil)

	// NGoroutines is not updated right away, so we need to wait before failing
	t := time.After(30 * time.Second)
	for {
		select {
		case <-t:
			n := getNGoroutines()
			c.Assert(n <= nroutines, checker.Equals, true, check.Commentf("leaked goroutines: expected less than or equal to %d, got: %d", nroutines, n))

		default:
			if n := getNGoroutines(); n <= nroutines {
				return
			}
			time.Sleep(200 * time.Millisecond)
		}
	}
}

func (s *DockerSuite) TestLogsFollowGoroutinesNoOutput(c *check.C) {
	testRequires(c, DaemonIsLinux)
	out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "while true; do sleep 2; done")
	id := strings.TrimSpace(out)
	c.Assert(waitRun(id), checker.IsNil)

	type info struct {
		NGoroutines int
	}
	getNGoroutines := func() int {
		var i info
		status, b, err := sockRequest("GET", "/info", nil)
		c.Assert(err, checker.IsNil)
		c.Assert(status, checker.Equals, 200)
		c.Assert(json.Unmarshal(b, &i), checker.IsNil)
		return i.NGoroutines
	}

	nroutines := getNGoroutines()

	cmd := exec.Command(dockerBinary, "logs", "-f", id)
	c.Assert(cmd.Start(), checker.IsNil)
	time.Sleep(200 * time.Millisecond)
	c.Assert(cmd.Process.Kill(), checker.IsNil)

	// NGoroutines is not updated right away, so we need to wait before failing
	t := time.After(30 * time.Second)
	for {
		select {
		case <-t:
			n := getNGoroutines()
			c.Assert(n <= nroutines, checker.Equals, true, check.Commentf("leaked goroutines: expected less than or equal to %d, got: %d", nroutines, n))

		default:
			if n := getNGoroutines(); n <= nroutines {
				return
			}
			time.Sleep(200 * time.Millisecond)
		}
	}
}

func (s *DockerSuite) TestLogsCLIContainerNotFound(c *check.C) {
	name := "testlogsnocontainer"
	out, _, _ := dockerCmdWithError("logs", name)
	message := fmt.Sprintf(".*No such container: %s.*\n", name)
	c.Assert(out, checker.Matches, message)
}
<commit_msg>Fix flaky test TestLogsSince<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io"
	"os/exec"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/docker/docker/pkg/integration/checker"
	"github.com/docker/docker/pkg/timeutils"
	"github.com/go-check/check"
)

// This used to work, it test a log of PageSize-1 (gh#4851)
func (s *DockerSuite) TestLogsContainerSmallerThanPage(c *check.C) {
	testRequires(c, DaemonIsLinux)
	testLen := 32767
	out, _ := dockerCmd(c, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("for i in $(seq 1 %d); do echo -n =; done; echo", testLen))

	id := strings.TrimSpace(out)
	dockerCmd(c, "wait", id)

	out, _ = dockerCmd(c, "logs", id)

	c.Assert(out, checker.HasLen, testLen+1)
}

// Regression test: When going over the PageSize, it used to panic (gh#4851)
func (s *DockerSuite) TestLogsContainerBiggerThanPage(c *check.C) {
	testRequires(c, DaemonIsLinux)
	testLen := 32768
	out, _ := dockerCmd(c, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("for i in $(seq 1 %d); do echo -n =; done; echo", testLen))

	id := strings.TrimSpace(out)
	dockerCmd(c, "wait", id)

	out, _ = dockerCmd(c, "logs", id)

	c.Assert(out, checker.HasLen, testLen+1)
}

// Regression test: When going much over the PageSize, it used to block (gh#4851)
func (s *DockerSuite) TestLogsContainerMuchBiggerThanPage(c *check.C) {
	testRequires(c, DaemonIsLinux)
	testLen := 33000
	out, _ := dockerCmd(c, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("for i in $(seq 1 %d); do echo -n =; done; echo", testLen))

	id := strings.TrimSpace(out)
	dockerCmd(c, "wait", id)

	out, _ = dockerCmd(c, "logs", id)

	c.Assert(out, checker.HasLen, testLen+1)
}

func (s *DockerSuite) TestLogsTimestamps(c *check.C) {
	testRequires(c, DaemonIsLinux)
	testLen := 100
	out, _ := dockerCmd(c, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("for i in $(seq 1 %d); do echo =; done;", testLen))

	id := strings.TrimSpace(out)
	dockerCmd(c, "wait", id)

	out, _ = dockerCmd(c, "logs", "-t", id)

	lines := strings.Split(out, "\n")

	c.Assert(lines, checker.HasLen, testLen+1)

	ts := regexp.MustCompile(`^.* `)

	for _, l := range lines {
		if l != "" {
			_, err := time.Parse(timeutils.RFC3339NanoFixed+" ", ts.FindString(l))
			c.Assert(err, checker.IsNil, check.Commentf("Failed to parse timestamp from %v", l))
			// ensure we have padded 0's
			c.Assert(l[29], checker.Equals, uint8('Z'))
		}
	}
}

func (s *DockerSuite) TestLogsSeparateStderr(c *check.C) {
	testRequires(c, DaemonIsLinux)
	msg := "stderr_log"
	out, _ := dockerCmd(c, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("echo %s 1>&2", msg))

	id := strings.TrimSpace(out)
	dockerCmd(c, "wait", id)

	stdout, stderr, _ := dockerCmdWithStdoutStderr(c, "logs", id)

	c.Assert(stdout, checker.Equals, "")

	stderr = strings.TrimSpace(stderr)

	c.Assert(stderr, checker.Equals, msg)
}

func (s *DockerSuite) TestLogsStderrInStdout(c *check.C) {
	testRequires(c, DaemonIsLinux)
	msg := "stderr_log"
	out, _ := dockerCmd(c, "run", "-d", "-t", "busybox", "sh", "-c", fmt.Sprintf("echo %s 1>&2", msg))

	id := strings.TrimSpace(out)
	dockerCmd(c, "wait", id)

	stdout, stderr, _ := dockerCmdWithStdoutStderr(c, "logs", id)
	c.Assert(stderr, checker.Equals, "")

	stdout = strings.TrimSpace(stdout)
	c.Assert(stdout, checker.Equals, msg)
}

func (s *DockerSuite) TestLogsTail(c *check.C) {
	testRequires(c, DaemonIsLinux)
	testLen := 100
	out, _ := dockerCmd(c, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("for i in $(seq 1 %d); do echo =; done;", testLen))

	id := strings.TrimSpace(out)
	dockerCmd(c, "wait", id)

	out, _ = dockerCmd(c, "logs", "--tail", "5", id)

	lines := strings.Split(out, "\n")

	c.Assert(lines, checker.HasLen, 6)

	out, _ = dockerCmd(c, "logs", "--tail", "all", id)

	lines = strings.Split(out, "\n")

	c.Assert(lines, checker.HasLen, testLen+1)

	out, _, _ = dockerCmdWithStdoutStderr(c, "logs", "--tail", "random", id)

	lines = strings.Split(out, "\n")

	c.Assert(lines, checker.HasLen, testLen+1)
}

func (s *DockerSuite) TestLogsFollowStopped(c *check.C) {
	testRequires(c, DaemonIsLinux)
	out, _ := dockerCmd(c, "run", "-d", "busybox", "echo", "hello")

	id := strings.TrimSpace(out)
	dockerCmd(c, "wait", id)

	logsCmd := exec.Command(dockerBinary, "logs", "-f", id)
	c.Assert(logsCmd.Start(), checker.IsNil)

	errChan := make(chan error)
	go func() {
		errChan <- logsCmd.Wait()
		close(errChan)
	}()

	select {
	case err := <-errChan:
		c.Assert(err, checker.IsNil)
	case <-time.After(1 * time.Second):
		c.Fatal("Following logs is hanged")
	}
}

func (s *DockerSuite) TestLogsSince(c *check.C) {
	testRequires(c, DaemonIsLinux)
	name := "testlogssince"
	dockerCmd(c, "run", "--name="+name, "busybox", "/bin/sh", "-c", "for i in $(seq 1 3); do sleep 2; echo log$i; done")
	out, _ := dockerCmd(c, "logs", "-t", name)

	log2Line := strings.Split(strings.Split(out, "\n")[1], " ")
	t, err := time.Parse(time.RFC3339Nano, log2Line[0]) // the timestamp log2 is written
	c.Assert(err, checker.IsNil)
	since := t.Unix() + 1 // add 1s so log1 & log2 doesn't show up
	out, _ = dockerCmd(c, "logs", "-t", fmt.Sprintf("--since=%v", since), name)

	// Skip 2 seconds
	unexpected := []string{"log1", "log2"}
	for _, v := range unexpected {
		c.Assert(out, checker.Not(checker.Contains), v, check.Commentf("unexpected log message returned, since=%v", since))
	}

	// Test to make sure a bad since format is caught by the client
	out, _, _ = dockerCmdWithError("logs", "-t", "--since=2006-01-02T15:04:0Z", name)
	c.Assert(out, checker.Contains, "cannot parse \"0Z\" as \"05\"", check.Commentf("bad since format passed to server"))

	// Test with default value specified and parameter omitted
	expected := []string{"log1", "log2", "log3"}
	for _, cmd := range []*exec.Cmd{
		exec.Command(dockerBinary, "logs", "-t", name),
		exec.Command(dockerBinary, "logs", "-t", "--since=0", name),
	} {
		out, _, err = runCommandWithOutput(cmd)
		c.Assert(err, checker.IsNil, check.Commentf("failed to log container: %s", out))
		for _, v := range expected {
			c.Assert(out, checker.Contains, v)
		}
	}
}

func (s *DockerSuite) TestLogsSinceFutureFollow(c *check.C) {
	testRequires(c, DaemonIsLinux)
	out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", `for i in $(seq 1 5); do date +%s; sleep 1; done`)
	id := strings.TrimSpace(out)

	now := daemonTime(c).Unix()
	since := now + 2
	out, _ = dockerCmd(c, "logs", "-f", fmt.Sprintf("--since=%v", since), id)
	lines := strings.Split(strings.TrimSpace(out), "\n")
	c.Assert(lines, checker.Not(checker.HasLen), 0)
	for _, v := range lines {
		ts, err := strconv.ParseInt(v, 10, 64)
		c.Assert(err, checker.IsNil, check.Commentf("cannot parse timestamp output from log: '%v'\nout=%s", v, out))
		c.Assert(ts >= since, checker.Equals, true, check.Commentf("earlier log found. since=%v logdate=%v", since, ts))
	}
}

// Regression test for #8832
func (s *DockerSuite) TestLogsFollowSlowStdoutConsumer(c *check.C) {
	testRequires(c, DaemonIsLinux)
	out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", `usleep 600000;yes X | head -c 200000`)

	id := strings.TrimSpace(out)

	stopSlowRead := make(chan bool)

	go func() {
		exec.Command(dockerBinary, "wait", id).Run()
		stopSlowRead <- true
	}()

	logCmd := exec.Command(dockerBinary, "logs", "-f", id)
	stdout, err := logCmd.StdoutPipe()
	c.Assert(err, checker.IsNil)
	c.Assert(logCmd.Start(), checker.IsNil)

	// First read slowly
	bytes1, err := consumeWithSpeed(stdout, 10, 50*time.Millisecond, stopSlowRead)
	c.Assert(err, checker.IsNil)

	// After the container has finished we can continue reading fast
	bytes2, err := consumeWithSpeed(stdout, 32*1024, 0, nil)
	c.Assert(err, checker.IsNil)

	actual := bytes1 + bytes2
	expected := 200000
	c.Assert(actual, checker.Equals, expected)

}

func (s *DockerSuite) TestLogsFollowGoroutinesWithStdout(c *check.C) {
	testRequires(c, DaemonIsLinux)
	out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "while true; do echo hello; sleep 2; done")
	id := strings.TrimSpace(out)
	c.Assert(waitRun(id), checker.IsNil)

	type info struct {
		NGoroutines int
	}
	getNGoroutines := func() int {
		var i info
		status, b, err := sockRequest("GET", "/info", nil)
		c.Assert(err, checker.IsNil)
		c.Assert(status, checker.Equals, 200)
		c.Assert(json.Unmarshal(b, &i), checker.IsNil)
		return i.NGoroutines
	}

	nroutines := getNGoroutines()

	cmd := exec.Command(dockerBinary, "logs", "-f", id)
	r, w := io.Pipe()
	cmd.Stdout = w
	c.Assert(cmd.Start(), checker.IsNil)

	// Make sure pipe is written to
	chErr := make(chan error)
	go func() {
		b := make([]byte, 1)
		_, err := r.Read(b)
		chErr <- err
	}()
	c.Assert(<-chErr, checker.IsNil)
	c.Assert(cmd.Process.Kill(), checker.IsNil)

	// NGoroutines is not updated right away, so we need to wait before failing
	t := time.After(30 * time.Second)
	for {
		select {
		case <-t:
			n := getNGoroutines()
			c.Assert(n <= nroutines, checker.Equals, true, check.Commentf("leaked goroutines: expected less than or equal to %d, got: %d", nroutines, n))

		default:
			if n := getNGoroutines(); n <= nroutines {
				return
			}
			time.Sleep(200 * time.Millisecond)
		}
	}
}

func (s *DockerSuite) TestLogsFollowGoroutinesNoOutput(c *check.C) {
	testRequires(c, DaemonIsLinux)
	out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "while true; do sleep 2; done")
	id := strings.TrimSpace(out)
	c.Assert(waitRun(id), checker.IsNil)

	type info struct {
		NGoroutines int
	}
	getNGoroutines := func() int {
		var i info
		status, b, err := sockRequest("GET", "/info", nil)
		c.Assert(err, checker.IsNil)
		c.Assert(status, checker.Equals, 200)
		c.Assert(json.Unmarshal(b, &i), checker.IsNil)
		return i.NGoroutines
	}

	nroutines := getNGoroutines()

	cmd := exec.Command(dockerBinary, "logs", "-f", id)
	c.Assert(cmd.Start(), checker.IsNil)
	time.Sleep(200 * time.Millisecond)
	c.Assert(cmd.Process.Kill(), checker.IsNil)

	// NGoroutines is not updated right away, so we need to wait before failing
	t := time.After(30 * time.Second)
	for {
		select {
		case <-t:
			n := getNGoroutines()
			c.Assert(n <= nroutines, checker.Equals, true, check.Commentf("leaked goroutines: expected less than or equal to %d, got: %d", nroutines, n))

		default:
			if n := getNGoroutines(); n <= nroutines {
				return
			}
			time.Sleep(200 * time.Millisecond)
		}
	}
}

func (s *DockerSuite) TestLogsCLIContainerNotFound(c *check.C) {
	name := "testlogsnocontainer"
	out, _, _ := dockerCmdWithError("logs", name)
	message := fmt.Sprintf(".*No such container: %s.*\n", name)
	c.Assert(out, checker.Matches, message)
}
<|endoftext|>


<commit_before>/* Ranges parses ranges of the form -n,n,n-n,n- (or -).  See the manpage for
cut(1) for more info.

Example:
 TODO: Finish this

 Bug: There really should be some sort of optimization for the filter.
*/
package ranges

import (
	"fmt"
	"strings"
)

/* ranges.go
 * library to parse range strings of the form -n,n,n-n,n- or -
 * by J. Stuart McMurray
 * Created 20141119
 * Last modified 20141119
 *
 * Copyright (c) 2014 J. Stuart McMurray <kd5pbo@gmail.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/* Irange represents a range of input */
type IRange struct {
	Start int
	End   int
}

/* Has returns whether or not n is in the range specified by i */
func (i IRange) Has(n int) bool {
	return (n <= end) && (n >= start)
}

/* Stringify IRange */
func (i IRange) String() {
	fmt.Sprintf("%v-%v", i.Start, i.End)
}

/* Filter for ranges and indices */
type Filter struct {
	All          bool     /* - */
	Upto         int      /* -n */
	Singles      []int    /* n,n,n,n */
	Ranges       []irange /* n-n,n-n */
	Andfollowing int      /* n- */

	/* Printf-like functions to print Information and Debugging messages */
	Debug   func(f string, a ...interface{})
	Verbose func(f string, a ...interface{})
}

/* New makes a new Filter, with the Debug and Verbose functions set to d and v,
which may be nil to indicate a no-op. */
func New(d, v func(f string, a ...interface{})) Filter {
	f := Filter{}
	if nil == d {
		d = func(f string, a ...interface{}) {}
	}
	if nil == v {
		v = func(f string, a ...interface{}) {}
	}
	f.Debug = d
	f.Verbose = v
}

/* Stringify the filter to a one-line string */
func (f Filter) String() string {
	/* TODO: Finish this */
	return fmt.Sprintf("%v", f)
}

/* Pretty-print the filter */
func (f Filter) PPrint() {
	/* TODO: Finish this */
	fmt.Printf("%v\n", f)
}

/* Update the filter with the ranges in s.  It is a union operation.  It is
an error to pass a string to Update which doesn't contain at least one
range. */
func (f *Filter) Update(s string) error {
	one := false /* Have at least one range */
	/* Trim Whitespace */
	s = strings.TrimSpace(s)
	/* Split on , */
	ss = strings.Split(s, ",")
	if 0 == len(ss) {
		return Errors.New("no ranges")
	}
	f.Verbose("Processing %v", s)
	/* Process each string in ss */
	for _, r := range ss {
		/* Skip whitespace-only strings */
		s = strings.TrimSpace(s)
		if len(s) > 0 {
			/* Die on errors */
			if err := f.UpdateOne(s); err != nil {
				return err
			}
			/* We got one */
			one = true
		}
	}
}

/* UpdateOne adds to the filter the number or range in s.  It is a union. */
func (f *Filter) UpdateOne(s string) error {
	/* Trim whitespace */
	s = strings.TrimSpace(s)
	/* Give up if string was only whitespace */
	if "" == s {
		return true
		f.Debug("Got whitespace.")
	}
	f.Debug("Processing %v", s)
	/* Work out what sort of specification: -, -n, n-, n-n, n */
	switch {
	case "-" == s: /* - */
		f.all = true
		f.Verbose("Entire input selected")

	case strings.HasPrefix(s, "-"): /* -n */
		/* Extract the number */
		n, err := strconv.Atoi(strings.TrimLeft(s, "-"))
		if err != nil {
			return err
		}
		/* Don't change if it's a subset */
		if f.all || (f.upto >= n) {
			return nil
		}
		/* Update */
		f.upto = n
		f.Verbose("Final range now %v", s)

	case strings.HasSuffix(s, "-"): /* n- */
		/* Extract the number */
		n, err := strconv.Atoi(strings.TrimLeft(s, "-"))
		if err != nil {
			return err
		}
		/* Don't change if it's a subset */
		if f.all || (f.andfollowing <= n) {
			return nil
		}
		/* Update */
		f.andfollowing = n
		f.Verbose("Initial range now %v", s)

	case strings.ContainsRune(s, '-'): /* n-n */
		/* Extract the strings */
		ns := strings.SplitN(s, "-", 2)
		/* Make sure the split worked */
		if 2 != len(ns) { /* Should never happen */
			return errors.New("not enough numbers in range")
		}
		/* Extract the numbers */
		start, err := strings.Atoi(ns[0])
		if err != nil {
			return err
		}
		end, err := strings.Atoi(ns[1])
		if err != nil {
			return err
		}
		/* Check the obvious fields, optimize will do the rest */
		if f.all {
			return nil
		}
		if f.upto >= end {
			return nil
		}
		if f.andfollowing <= start {
			return nil
		}
		/* Add it to the list */
		f.ranges = append(f.ranges, irange{start: start, end: end})
		f.Verbose("Added range %v", s)

	default: /* n, hopefully */
		/* Extract the number */
		n, err := strconv.Atoi(s)
		if err != nil {
			return err
		}
		/* Check the obvious fields */
		if f.all || n <= f.upto || n >= f.andfollowing {
			return nil
		}
		/* Add if it not there */
		if !f.Allows(n) {
			f.singles = append(f.singles, n)
		}
		f.Verbose("Added index %v")

	}
	f.Debug("filter: %v", f)
}

/* Allows returns whether or not f allows n */
func (f filter) Allows(n int) {
	/* Check the obvious fields */
	if f.all || n <= f.upto || n >= f.andfollowing {
		return true
	}
	/* Check each range */
	if f.inRanges(n) {
		return true
	}
	/* Check the individual indices */
	for _, i := range f.singles {
		if n == i {
			return true
		}
	}
	/* If we're here, it's not allowed */
	return false
}

/* InRanges tests if in an index is in one of f's ranges */
func (f filter) InRanges(i int) {
	for _, r := range f.ranges {
		if i >= r.start && i <= r.end {
			return true
		}
	}
	return false
}
<commit_msg>Prettier documentation<commit_after>/*
Ranges parses ranges of the form -n,n,n-n,n- (or -).  See the manpage for
cut(1) for more info.

Example:
 TODO: Finish this

Bug: There really should be some sort of optimization for the filter.
*/
package ranges

import (
	"fmt"
	"strings"
)

/* ranges.go
 * library to parse range strings of the form -n,n,n-n,n- or -
 * by J. Stuart McMurray
 * Created 20141119
 * Last modified 20141119
 *
 * Copyright (c) 2014 J. Stuart McMurray <kd5pbo@gmail.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/* Irange represents a range of input */
type IRange struct {
	Start int
	End   int
}

/* Has returns whether or not n is in the range specified by i */
func (i IRange) Has(n int) bool {
	return (n <= end) && (n >= start)
}

/* Stringify IRange */
func (i IRange) String() {
	fmt.Sprintf("%v-%v", i.Start, i.End)
}

/* Filter for ranges and indices */
type Filter struct {
	All          bool     /* - */
	Upto         int      /* -n */
	Singles      []int    /* n,n,n,n */
	Ranges       []irange /* n-n,n-n */
	Andfollowing int      /* n- */

	/* Printf-like functions to print Information and Debugging messages */
	Debug   func(f string, a ...interface{})
	Verbose func(f string, a ...interface{})
}

/* New makes a new Filter, with the Debug and Verbose functions set to d and v,
which may be nil to indicate a no-op. */
func New(d, v func(f string, a ...interface{})) Filter {
	f := Filter{}
	if nil == d {
		d = func(f string, a ...interface{}) {}
	}
	if nil == v {
		v = func(f string, a ...interface{}) {}
	}
	f.Debug = d
	f.Verbose = v
}

/* Stringify the filter to a one-line string */
func (f Filter) String() string {
	/* TODO: Finish this */
	return fmt.Sprintf("%v", f)
}

/* Pretty-print the filter */
func (f Filter) PPrint() {
	/* TODO: Finish this */
	fmt.Printf("%v\n", f)
}

/* Update the filter with the ranges in s.  It is a union operation.  It is
an error to pass a string to Update which doesn't contain at least one
range. */
func (f *Filter) Update(s string) error {
	one := false /* Have at least one range */
	/* Trim Whitespace */
	s = strings.TrimSpace(s)
	/* Split on , */
	ss = strings.Split(s, ",")
	if 0 == len(ss) {
		return Errors.New("no ranges")
	}
	f.Verbose("Processing %v", s)
	/* Process each string in ss */
	for _, r := range ss {
		/* Skip whitespace-only strings */
		s = strings.TrimSpace(s)
		if len(s) > 0 {
			/* Die on errors */
			if err := f.UpdateOne(s); err != nil {
				return err
			}
			/* We got one */
			one = true
		}
	}
}

/* UpdateOne adds to the filter the number or range in s.  It is a union. */
func (f *Filter) UpdateOne(s string) error {
	/* Trim whitespace */
	s = strings.TrimSpace(s)
	/* Give up if string was only whitespace */
	if "" == s {
		return true
		f.Debug("Got whitespace.")
	}
	f.Debug("Processing %v", s)
	/* Work out what sort of specification: -, -n, n-, n-n, n */
	switch {
	case "-" == s: /* - */
		f.all = true
		f.Verbose("Entire input selected")

	case strings.HasPrefix(s, "-"): /* -n */
		/* Extract the number */
		n, err := strconv.Atoi(strings.TrimLeft(s, "-"))
		if err != nil {
			return err
		}
		/* Don't change if it's a subset */
		if f.all || (f.upto >= n) {
			return nil
		}
		/* Update */
		f.upto = n
		f.Verbose("Final range now %v", s)

	case strings.HasSuffix(s, "-"): /* n- */
		/* Extract the number */
		n, err := strconv.Atoi(strings.TrimLeft(s, "-"))
		if err != nil {
			return err
		}
		/* Don't change if it's a subset */
		if f.all || (f.andfollowing <= n) {
			return nil
		}
		/* Update */
		f.andfollowing = n
		f.Verbose("Initial range now %v", s)

	case strings.ContainsRune(s, '-'): /* n-n */
		/* Extract the strings */
		ns := strings.SplitN(s, "-", 2)
		/* Make sure the split worked */
		if 2 != len(ns) { /* Should never happen */
			return errors.New("not enough numbers in range")
		}
		/* Extract the numbers */
		start, err := strings.Atoi(ns[0])
		if err != nil {
			return err
		}
		end, err := strings.Atoi(ns[1])
		if err != nil {
			return err
		}
		/* Check the obvious fields, optimize will do the rest */
		if f.all {
			return nil
		}
		if f.upto >= end {
			return nil
		}
		if f.andfollowing <= start {
			return nil
		}
		/* Add it to the list */
		f.ranges = append(f.ranges, irange{start: start, end: end})
		f.Verbose("Added range %v", s)

	default: /* n, hopefully */
		/* Extract the number */
		n, err := strconv.Atoi(s)
		if err != nil {
			return err
		}
		/* Check the obvious fields */
		if f.all || n <= f.upto || n >= f.andfollowing {
			return nil
		}
		/* Add if it not there */
		if !f.Allows(n) {
			f.singles = append(f.singles, n)
		}
		f.Verbose("Added index %v")

	}
	f.Debug("filter: %v", f)
}

/* Allows returns whether or not f allows n */
func (f filter) Allows(n int) {
	/* Check the obvious fields */
	if f.all || n <= f.upto || n >= f.andfollowing {
		return true
	}
	/* Check each range */
	if f.inRanges(n) {
		return true
	}
	/* Check the individual indices */
	for _, i := range f.singles {
		if n == i {
			return true
		}
	}
	/* If we're here, it's not allowed */
	return false
}

/* InRanges tests if in an index is in one of f's ranges */
func (f filter) InRanges(i int) {
	for _, r := range f.ranges {
		if i >= r.start && i <= r.end {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>/*
Copyright 2015 Google Inc. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package bigtable

import (
	"flag"
	"fmt"
	"reflect"
	"sort"
	"strings"
	"testing"
	"time"

	"github.com/golang/protobuf/proto"
	"golang.org/x/net/context"
	"google.golang.org/cloud/bigtable/bttest"
	btspb "google.golang.org/cloud/bigtable/internal/service_proto"
)

func dataChunk(fam, col string, ts int64, data string) string {
	return fmt.Sprintf("chunks:<row_contents:<name:%q columns:<qualifier:%q cells:<timestamp_micros:%d value:%q>>>>", fam, col, ts, data)
}

func commit() string { return "chunks:<commit_row:true>" }

var chunkTests = []struct {
	desc   string
	chunks []string // sequence of ReadRowsResponse protos in text format
	want   map[string]Row
}{
	{
		desc: "single row single chunk",
		chunks: []string{
			`row_key: "row1" ` + dataChunk("fam", "col1", 1428382701000000, "data") + commit(),
		},
		want: map[string]Row{
			"row1": Row{
				"fam": []ReadItem{{
					Row:       "row1",
					Column:    "fam:col1",
					Timestamp: 1428382701000000,
					Value:     []byte("data"),
				}},
			},
		},
	},
	{
		desc: "single row multiple chunks",
		chunks: []string{
			`row_key: "row1" ` + dataChunk("fam", "col1", 1428382701000000, "data"),
			`row_key: "row1" ` + dataChunk("fam", "col2", 1428382702000000, "more data"),
			`row_key: "row1" ` + commit(),
		},
		want: map[string]Row{
			"row1": Row{
				"fam": []ReadItem{
					{
						Row:       "row1",
						Column:    "fam:col1",
						Timestamp: 1428382701000000,
						Value:     []byte("data"),
					},
					{
						Row:       "row1",
						Column:    "fam:col2",
						Timestamp: 1428382702000000,
						Value:     []byte("more data"),
					},
				},
			},
		},
	},
	// TODO(dsymonds): More test cases, including
	//	- multiple rows
	//	- reset_row
}

func TestChunkReader(t *testing.T) {
	for _, tc := range chunkTests {
		cr := new(chunkReader)
		got := make(map[string]Row)
		for i, txt := range tc.chunks {
			rrr := new(btspb.ReadRowsResponse)
			if err := proto.UnmarshalText(txt, rrr); err != nil {
				t.Fatalf("%s: internal error: bad #%d test text: %v", tc.desc, i, err)
			}
			if row := cr.process(rrr); row != nil {
				got[row.Key()] = row
			}
		}
		// TODO(dsymonds): check for partial rows?
		if !reflect.DeepEqual(got, tc.want) {
			t.Errorf("%s: processed response mismatch.\n got %+v\nwant %+v", tc.desc, got, tc.want)
		}
	}
}

func TestPrefix(t *testing.T) {
	tests := []struct {
		prefix, succ string
	}{
		{"", ""},
		{"\xff", ""}, // when used, "" means Infinity
		{"x\xff", "y"},
		{"\xfe", "\xff"},
	}
	for _, tc := range tests {
		got := prefixSuccessor(tc.prefix)
		if got != tc.succ {
			t.Errorf("prefixSuccessor(%q) = %q, want %s", tc.prefix, got, tc.succ)
			continue
		}
		r := PrefixRange(tc.prefix)
		if tc.succ == "" && r.limit != "" {
			t.Errorf("PrefixRange(%q) got limit %q", tc.prefix, r.limit)
		}
		if tc.succ != "" && r.limit != tc.succ {
			t.Errorf("PrefixRange(%q) got limit %q, want %q", tc.prefix, r.limit, tc.succ)
		}
	}
}

var useProd = flag.String("use_prod", "", `if set to "proj,zone,cluster,table", run integration test against production`)

func TestClientIntegration(t *testing.T) {
	proj, zone, cluster, table := "proj", "zone", "cluster", "mytable"
	var clientOpts []ClientOption
	timeout := 10 * time.Second
	if *useProd == "" {
		srv, err := bttest.NewServer()
		if err != nil {
			t.Fatal(err)
		}
		defer srv.Close()
		t.Logf("bttest.Server running on %s", srv.Addr)
		clientOpts = []ClientOption{WithCredentials(nil), WithInsecureAddr(srv.Addr)}
	} else {
		t.Logf("Running test against production")
		a := strings.Split(*useProd, ",")
		proj, zone, cluster, table = a[0], a[1], a[2], a[3]
		timeout = 1 * time.Minute
	}

	ctx, _ := context.WithTimeout(context.Background(), timeout)

	client, err := NewClient(ctx, proj, zone, cluster, clientOpts...)
	if err != nil {
		t.Fatalf("NewClient: %v", err)
	}
	defer client.Close()

	adminClient, err := NewAdminClient(ctx, proj, zone, cluster, clientOpts...)
	if err != nil {
		t.Fatalf("NewAdminClient: %v", err)
	}
	defer adminClient.Close()

	// Delete the table at the end of the test.
	// Do this even before creating the table so that if this is running
	// against production and CreateTable fails there's a chance of cleaning it up.
	defer adminClient.DeleteTable(ctx, table)

	if err := adminClient.CreateTable(ctx, table); err != nil {
		t.Fatalf("Creating table: %v", err)
	}
	if err := adminClient.CreateColumnFamily(ctx, table, "follows"); err != nil {
		t.Fatalf("Creating column family: %v", err)
	}

	tbl := client.Open(table)

	// Insert some data.
	initialData := map[string][]string{
		"wmckinley":   []string{"tjefferson"},
		"gwashington": []string{"jadams"},
		"tjefferson":  []string{"gwashington", "jadams"}, // wmckinley set conditionally below
		"jadams":      []string{"gwashington", "tjefferson"},
	}
	for row, ss := range initialData {
		mut := NewMutation()
		for _, name := range ss {
			mut.Set("follows", name, 0, []byte("1"))
		}
		if err := tbl.Apply(ctx, row, mut); err != nil {
			t.Errorf("Mutating row %q: %v", row, err)
		}
	}

	// Do a conditional mutation with a complex filter.
	mutTrue := NewMutation()
	mutTrue.Set("follows", "wmckinley", 0, []byte("1"))
	filter := ChainFilters(ColumnFilter("gwash[iz].*"), ValueFilter("."))
	mut := NewCondMutation(filter, mutTrue, nil)
	if err := tbl.Apply(ctx, "tjefferson", mut); err != nil {
		t.Errorf("Conditionally mutating row: %v", err)
	}
	// Do a second condition mutation with a filter that does not match,
	// and thus no changes should be made.
	mutTrue = NewMutation()
	mutTrue.DeleteRow()
	filter = ColumnFilter("snoop.dogg")
	mut = NewCondMutation(filter, mutTrue, nil)
	if err := tbl.Apply(ctx, "tjefferson", mut); err != nil {
		t.Errorf("Conditionally mutating row: %v", err)
	}

	// Fetch a row.
	row, err := tbl.ReadRow(ctx, "jadams")
	if err != nil {
		t.Fatalf("Reading a row: %v", err)
	}
	wantRow := Row{
		"follows": []ReadItem{
			{Row: "jadams", Column: "follows:gwashington", Value: []byte("1")},
			{Row: "jadams", Column: "follows:tjefferson", Value: []byte("1")},
		},
	}
	for _, ris := range row {
		sort.Sort(byColumn(ris))
	}
	if !reflect.DeepEqual(row, wantRow) {
		t.Errorf("Read row mismatch.\n got %#v\nwant %#v", row, wantRow)
	}

	// Do a bunch of reads with filters.
	readTests := []struct {
		desc   string
		rr     RowRange
		filter Filter // may be nil

		// We do the read, grab all the cells, turn them into "<row>-<col>-<val>",
		// sort that list, and join with a comma.
		want string
	}{
		{
			desc: "read all, unfiltered",
			rr:   RowRange{},
			want: "gwashington-jadams-1,jadams-gwashington-1,jadams-tjefferson-1,tjefferson-gwashington-1,tjefferson-jadams-1,tjefferson-wmckinley-1,wmckinley-tjefferson-1",
		},
		{
			desc: "read with InfiniteRange, unfiltered",
			rr:   InfiniteRange("tjefferson"),
			want: "tjefferson-gwashington-1,tjefferson-jadams-1,tjefferson-wmckinley-1,wmckinley-tjefferson-1",
		},
		{
			desc: "read with NewRange, unfiltered",
			rr:   NewRange("gargamel", "hubbard"),
			want: "gwashington-jadams-1",
		},
		{
			desc: "read with PrefixRange, unfiltered",
			rr:   PrefixRange("jad"),
			want: "jadams-gwashington-1,jadams-tjefferson-1",
		},
		{
			desc: "read with SingleRow, unfiltered",
			rr:   SingleRow("wmckinley"),
			want: "wmckinley-tjefferson-1",
		},
		{
			desc:   "read all, with ColumnFilter",
			rr:     RowRange{},
			filter: ColumnFilter(".*j.*"), // matches "jadams" and "tjefferson"
			want:   "gwashington-jadams-1,jadams-tjefferson-1,tjefferson-jadams-1,wmckinley-tjefferson-1",
		},
	}
	for _, tc := range readTests {
		var opts []ReadOption
		if tc.filter != nil {
			opts = append(opts, RowFilter(tc.filter))
		}
		var elt []string
		err := tbl.ReadRows(context.Background(), tc.rr, func(r Row) bool {
			for _, ris := range r {
				for _, ri := range ris {
					// Use the column qualifier only to make the test data briefer.
					col := ri.Column[strings.Index(ri.Column, ":")+1:]
					x := fmt.Sprintf("%s-%s-%s", ri.Row, col, ri.Value)
					elt = append(elt, x)
				}
			}
			return true
		}, opts...)
		if err != nil {
			t.Errorf("%s: %v", tc.desc, err)
			continue
		}
		sort.Strings(elt)
		if got := strings.Join(elt, ","); got != tc.want {
			t.Errorf("%s: wrong reads.\n got %q\nwant %q", tc.desc, got, tc.want)
		}
	}

	// Check ReadModifyWrite.

	if err := adminClient.CreateColumnFamily(ctx, table, "counter"); err != nil {
		t.Fatalf("Creating column family: %v", err)
	}

	appendRMW := func(b []byte) *ReadModifyWrite {
		rmw := NewReadModifyWrite()
		rmw.AppendValue("counter", "likes", b)
		return rmw
	}
	incRMW := func(n int64) *ReadModifyWrite {
		rmw := NewReadModifyWrite()
		rmw.Increment("counter", "likes", n)
		return rmw
	}
	rmwSeq := []struct {
		desc string
		rmw  *ReadModifyWrite
		want []byte
	}{
		{
			desc: "append #1",
			rmw:  appendRMW([]byte{0, 0, 0}),
			want: []byte{0, 0, 0},
		},
		{
			desc: "append #2",
			rmw:  appendRMW([]byte{0, 0, 0, 0, 17}), // the remaining 40 bits to make a big-endian 17
			want: []byte{0, 0, 0, 0, 0, 0, 0, 17},
		},
		{
			desc: "increment",
			rmw:  incRMW(8),
			want: []byte{0, 0, 0, 0, 0, 0, 0, 25},
		},
	}
	for _, step := range rmwSeq {
		row, err := tbl.ApplyReadModifyWrite(ctx, "gwashington", step.rmw)
		if err != nil {
			t.Fatalf("ApplyReadModifyWrite %+v: %v", step.rmw, err)
		}
		clearTimestamps(row)
		wantRow := Row{"counter": []ReadItem{{Row: "gwashington", Column: "counter:likes", Value: step.want}}}
		if !reflect.DeepEqual(row, wantRow) {
			t.Fatalf("After %s,\n got %v\nwant %v", step.desc, row, wantRow)
		}
	}
}

type byColumn []ReadItem

func (b byColumn) Len() int           { return len(b) }
func (b byColumn) Swap(i, j int)      { b[i], b[j] = b[j], b[i] }
func (b byColumn) Less(i, j int) bool { return b[i].Column < b[j].Column }

func clearTimestamps(r Row) {
	for _, ris := range r {
		for i := range ris {
			ris[i].Timestamp = 0
		}
	}
}
<commit_msg>bigtable: Verify that returning false from the ReadRows callback actually stops the read.<commit_after>/*
Copyright 2015 Google Inc. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package bigtable

import (
	"flag"
	"fmt"
	"reflect"
	"sort"
	"strings"
	"testing"
	"time"

	"github.com/golang/protobuf/proto"
	"golang.org/x/net/context"
	"google.golang.org/cloud/bigtable/bttest"
	btspb "google.golang.org/cloud/bigtable/internal/service_proto"
)

func dataChunk(fam, col string, ts int64, data string) string {
	return fmt.Sprintf("chunks:<row_contents:<name:%q columns:<qualifier:%q cells:<timestamp_micros:%d value:%q>>>>", fam, col, ts, data)
}

func commit() string { return "chunks:<commit_row:true>" }

var chunkTests = []struct {
	desc   string
	chunks []string // sequence of ReadRowsResponse protos in text format
	want   map[string]Row
}{
	{
		desc: "single row single chunk",
		chunks: []string{
			`row_key: "row1" ` + dataChunk("fam", "col1", 1428382701000000, "data") + commit(),
		},
		want: map[string]Row{
			"row1": Row{
				"fam": []ReadItem{{
					Row:       "row1",
					Column:    "fam:col1",
					Timestamp: 1428382701000000,
					Value:     []byte("data"),
				}},
			},
		},
	},
	{
		desc: "single row multiple chunks",
		chunks: []string{
			`row_key: "row1" ` + dataChunk("fam", "col1", 1428382701000000, "data"),
			`row_key: "row1" ` + dataChunk("fam", "col2", 1428382702000000, "more data"),
			`row_key: "row1" ` + commit(),
		},
		want: map[string]Row{
			"row1": Row{
				"fam": []ReadItem{
					{
						Row:       "row1",
						Column:    "fam:col1",
						Timestamp: 1428382701000000,
						Value:     []byte("data"),
					},
					{
						Row:       "row1",
						Column:    "fam:col2",
						Timestamp: 1428382702000000,
						Value:     []byte("more data"),
					},
				},
			},
		},
	},
	// TODO(dsymonds): More test cases, including
	//	- multiple rows
	//	- reset_row
}

func TestChunkReader(t *testing.T) {
	for _, tc := range chunkTests {
		cr := new(chunkReader)
		got := make(map[string]Row)
		for i, txt := range tc.chunks {
			rrr := new(btspb.ReadRowsResponse)
			if err := proto.UnmarshalText(txt, rrr); err != nil {
				t.Fatalf("%s: internal error: bad #%d test text: %v", tc.desc, i, err)
			}
			if row := cr.process(rrr); row != nil {
				got[row.Key()] = row
			}
		}
		// TODO(dsymonds): check for partial rows?
		if !reflect.DeepEqual(got, tc.want) {
			t.Errorf("%s: processed response mismatch.\n got %+v\nwant %+v", tc.desc, got, tc.want)
		}
	}
}

func TestPrefix(t *testing.T) {
	tests := []struct {
		prefix, succ string
	}{
		{"", ""},
		{"\xff", ""}, // when used, "" means Infinity
		{"x\xff", "y"},
		{"\xfe", "\xff"},
	}
	for _, tc := range tests {
		got := prefixSuccessor(tc.prefix)
		if got != tc.succ {
			t.Errorf("prefixSuccessor(%q) = %q, want %s", tc.prefix, got, tc.succ)
			continue
		}
		r := PrefixRange(tc.prefix)
		if tc.succ == "" && r.limit != "" {
			t.Errorf("PrefixRange(%q) got limit %q", tc.prefix, r.limit)
		}
		if tc.succ != "" && r.limit != tc.succ {
			t.Errorf("PrefixRange(%q) got limit %q, want %q", tc.prefix, r.limit, tc.succ)
		}
	}
}

var useProd = flag.String("use_prod", "", `if set to "proj,zone,cluster,table", run integration test against production`)

func TestClientIntegration(t *testing.T) {
	proj, zone, cluster, table := "proj", "zone", "cluster", "mytable"
	var clientOpts []ClientOption
	timeout := 10 * time.Second
	if *useProd == "" {
		srv, err := bttest.NewServer()
		if err != nil {
			t.Fatal(err)
		}
		defer srv.Close()
		t.Logf("bttest.Server running on %s", srv.Addr)
		clientOpts = []ClientOption{WithCredentials(nil), WithInsecureAddr(srv.Addr)}
	} else {
		t.Logf("Running test against production")
		a := strings.Split(*useProd, ",")
		proj, zone, cluster, table = a[0], a[1], a[2], a[3]
		timeout = 1 * time.Minute
	}

	ctx, _ := context.WithTimeout(context.Background(), timeout)

	client, err := NewClient(ctx, proj, zone, cluster, clientOpts...)
	if err != nil {
		t.Fatalf("NewClient: %v", err)
	}
	defer client.Close()

	adminClient, err := NewAdminClient(ctx, proj, zone, cluster, clientOpts...)
	if err != nil {
		t.Fatalf("NewAdminClient: %v", err)
	}
	defer adminClient.Close()

	// Delete the table at the end of the test.
	// Do this even before creating the table so that if this is running
	// against production and CreateTable fails there's a chance of cleaning it up.
	defer adminClient.DeleteTable(ctx, table)

	if err := adminClient.CreateTable(ctx, table); err != nil {
		t.Fatalf("Creating table: %v", err)
	}
	if err := adminClient.CreateColumnFamily(ctx, table, "follows"); err != nil {
		t.Fatalf("Creating column family: %v", err)
	}

	tbl := client.Open(table)

	// Insert some data.
	initialData := map[string][]string{
		"wmckinley":   []string{"tjefferson"},
		"gwashington": []string{"jadams"},
		"tjefferson":  []string{"gwashington", "jadams"}, // wmckinley set conditionally below
		"jadams":      []string{"gwashington", "tjefferson"},
	}
	for row, ss := range initialData {
		mut := NewMutation()
		for _, name := range ss {
			mut.Set("follows", name, 0, []byte("1"))
		}
		if err := tbl.Apply(ctx, row, mut); err != nil {
			t.Errorf("Mutating row %q: %v", row, err)
		}
	}

	// Do a conditional mutation with a complex filter.
	mutTrue := NewMutation()
	mutTrue.Set("follows", "wmckinley", 0, []byte("1"))
	filter := ChainFilters(ColumnFilter("gwash[iz].*"), ValueFilter("."))
	mut := NewCondMutation(filter, mutTrue, nil)
	if err := tbl.Apply(ctx, "tjefferson", mut); err != nil {
		t.Errorf("Conditionally mutating row: %v", err)
	}
	// Do a second condition mutation with a filter that does not match,
	// and thus no changes should be made.
	mutTrue = NewMutation()
	mutTrue.DeleteRow()
	filter = ColumnFilter("snoop.dogg")
	mut = NewCondMutation(filter, mutTrue, nil)
	if err := tbl.Apply(ctx, "tjefferson", mut); err != nil {
		t.Errorf("Conditionally mutating row: %v", err)
	}

	// Fetch a row.
	row, err := tbl.ReadRow(ctx, "jadams")
	if err != nil {
		t.Fatalf("Reading a row: %v", err)
	}
	wantRow := Row{
		"follows": []ReadItem{
			{Row: "jadams", Column: "follows:gwashington", Value: []byte("1")},
			{Row: "jadams", Column: "follows:tjefferson", Value: []byte("1")},
		},
	}
	for _, ris := range row {
		sort.Sort(byColumn(ris))
	}
	if !reflect.DeepEqual(row, wantRow) {
		t.Errorf("Read row mismatch.\n got %#v\nwant %#v", row, wantRow)
	}

	// Do a bunch of reads with filters.
	readTests := []struct {
		desc   string
		rr     RowRange
		filter Filter // may be nil

		// We do the read, grab all the cells, turn them into "<row>-<col>-<val>",
		// sort that list, and join with a comma.
		want string
	}{
		{
			desc: "read all, unfiltered",
			rr:   RowRange{},
			want: "gwashington-jadams-1,jadams-gwashington-1,jadams-tjefferson-1,tjefferson-gwashington-1,tjefferson-jadams-1,tjefferson-wmckinley-1,wmckinley-tjefferson-1",
		},
		{
			desc: "read with InfiniteRange, unfiltered",
			rr:   InfiniteRange("tjefferson"),
			want: "tjefferson-gwashington-1,tjefferson-jadams-1,tjefferson-wmckinley-1,wmckinley-tjefferson-1",
		},
		{
			desc: "read with NewRange, unfiltered",
			rr:   NewRange("gargamel", "hubbard"),
			want: "gwashington-jadams-1",
		},
		{
			desc: "read with PrefixRange, unfiltered",
			rr:   PrefixRange("jad"),
			want: "jadams-gwashington-1,jadams-tjefferson-1",
		},
		{
			desc: "read with SingleRow, unfiltered",
			rr:   SingleRow("wmckinley"),
			want: "wmckinley-tjefferson-1",
		},
		{
			desc:   "read all, with ColumnFilter",
			rr:     RowRange{},
			filter: ColumnFilter(".*j.*"), // matches "jadams" and "tjefferson"
			want:   "gwashington-jadams-1,jadams-tjefferson-1,tjefferson-jadams-1,wmckinley-tjefferson-1",
		},
	}
	for _, tc := range readTests {
		var opts []ReadOption
		if tc.filter != nil {
			opts = append(opts, RowFilter(tc.filter))
		}
		var elt []string
		err := tbl.ReadRows(context.Background(), tc.rr, func(r Row) bool {
			for _, ris := range r {
				for _, ri := range ris {
					// Use the column qualifier only to make the test data briefer.
					col := ri.Column[strings.Index(ri.Column, ":")+1:]
					x := fmt.Sprintf("%s-%s-%s", ri.Row, col, ri.Value)
					elt = append(elt, x)
				}
			}
			return true
		}, opts...)
		if err != nil {
			t.Errorf("%s: %v", tc.desc, err)
			continue
		}
		sort.Strings(elt)
		if got := strings.Join(elt, ","); got != tc.want {
			t.Errorf("%s: wrong reads.\n got %q\nwant %q", tc.desc, got, tc.want)
		}
	}

	// Do a scan and stop part way through.
	// Verify that the ReadRows callback doesn't keep running.
	stopped := false
	err = tbl.ReadRows(ctx, InfiniteRange(""), func(r Row) bool {
		if r.Key() < "h" {
			return true
		}
		if !stopped {
			stopped = true
			return false
		}
		t.Errorf("ReadRows kept scanning to row %q after being told to stop", r.Key())
		return false
	})
	if err != nil {
		t.Errorf("Partial ReadRows: %v", err)
	}

	// Check ReadModifyWrite.

	if err := adminClient.CreateColumnFamily(ctx, table, "counter"); err != nil {
		t.Fatalf("Creating column family: %v", err)
	}

	appendRMW := func(b []byte) *ReadModifyWrite {
		rmw := NewReadModifyWrite()
		rmw.AppendValue("counter", "likes", b)
		return rmw
	}
	incRMW := func(n int64) *ReadModifyWrite {
		rmw := NewReadModifyWrite()
		rmw.Increment("counter", "likes", n)
		return rmw
	}
	rmwSeq := []struct {
		desc string
		rmw  *ReadModifyWrite
		want []byte
	}{
		{
			desc: "append #1",
			rmw:  appendRMW([]byte{0, 0, 0}),
			want: []byte{0, 0, 0},
		},
		{
			desc: "append #2",
			rmw:  appendRMW([]byte{0, 0, 0, 0, 17}), // the remaining 40 bits to make a big-endian 17
			want: []byte{0, 0, 0, 0, 0, 0, 0, 17},
		},
		{
			desc: "increment",
			rmw:  incRMW(8),
			want: []byte{0, 0, 0, 0, 0, 0, 0, 25},
		},
	}
	for _, step := range rmwSeq {
		row, err := tbl.ApplyReadModifyWrite(ctx, "gwashington", step.rmw)
		if err != nil {
			t.Fatalf("ApplyReadModifyWrite %+v: %v", step.rmw, err)
		}
		clearTimestamps(row)
		wantRow := Row{"counter": []ReadItem{{Row: "gwashington", Column: "counter:likes", Value: step.want}}}
		if !reflect.DeepEqual(row, wantRow) {
			t.Fatalf("After %s,\n got %v\nwant %v", step.desc, row, wantRow)
		}
	}
}

type byColumn []ReadItem

func (b byColumn) Len() int           { return len(b) }
func (b byColumn) Swap(i, j int)      { b[i], b[j] = b[j], b[i] }
func (b byColumn) Less(i, j int) bool { return b[i].Column < b[j].Column }

func clearTimestamps(r Row) {
	for _, ris := range r {
		for i := range ris {
			ris[i].Timestamp = 0
		}
	}
}
<|endoftext|>


<commit_before>package mocks

import (
	"fmt"
	auth3 "github.com/BytemarkHosting/auth-client"
	"github.com/BytemarkHosting/bytemark-client/lib"
	"github.com/BytemarkHosting/bytemark-client/lib/billing"
	"github.com/BytemarkHosting/bytemark-client/lib/brain"
	"github.com/BytemarkHosting/bytemark-client/lib/spp"
	mock "github.com/maraino/go-mock"
	"net/http"
	"net/url"
)

type Client struct {
	mock.Mock
}

func (c *Client) AllowInsecureRequests() {
	c.Called()
}
func (c *Client) BuildRequestNoAuth(method string, endpoint lib.Endpoint, path string, parts ...string) (*lib.Request, error) {
	r := c.Called(method, endpoint, path, parts)
	req, _ := r.Get(0).(*lib.Request)
	return req, r.Error(1)
}
func (c *Client) BuildRequest(method string, endpoint lib.Endpoint, path string, parts ...string) (*lib.Request, error) {
	r := c.Called(method, endpoint, path, parts)
	req, _ := r.Get(0).(*lib.Request)
	return req, r.Error(1)

}
func (c *Client) NewRequestNoAuth(method string, url *url.URL) *lib.Request {
	r := c.Called(method, url)
	req, _ := r.Get(0).(*lib.Request)
	return req
}
func (c *Client) NewRequest(method string, url *url.URL) *lib.Request {
	r := c.Called(method, url)
	req, _ := r.Get(0).(*lib.Request)
	return req
}

func (c *Client) GetEndpoint() string {
	r := c.Called()
	return r.String(0)
}
func (c *Client) GetSessionToken() string {
	r := c.Called()
	return r.String(0)
}
func (c *Client) GetSessionUser() string {
	r := c.Called()
	return r.String(0)
}
func (c *Client) GetSessionFactors() []string {
	r := c.Called()
	ar := r.Get(0)
	return ar.([]string)
}
func (c *Client) GetSPPToken(cc spp.CreditCard, owner *billing.Person) (string, error) {
	r := c.Called(cc, owner)
	return r.String(0), r.Error(1)
}
func (c *Client) SetDebugLevel(level int) {
	c.Called(level)
}
func (c *Client) AuthWithToken(token string) error {
	r := c.Called(token)
	return r.Error(0)
}
func (c *Client) AuthWithCredentials(credents auth3.Credentials) error {
	r := c.Called(credents)
	return r.Error(0)
}
func (c *Client) RequestAndUnmarshal(auth bool, method, path, requestBody string, output interface{}) error {
	r := c.Called(auth, method, path, requestBody, output)
	return r.Error(0)
}
func (c *Client) RequestAndRead(auth bool, method, path, requestBody string) (responseBody []byte, err error) {
	r := c.Called(auth, method, path, requestBody)
	return r.Bytes(0), r.Error(1)
}

func (c *Client) Request(auth bool, method string, location string, requestBody string) (req *http.Request, res *http.Response, err error) {
	r := c.Called(auth, method, location, requestBody)
	req, ok := r.Get(0).(*http.Request)
	if !ok {
		panic(fmt.Sprintf("Couldn't typecast request object because it was a %t", r.Get(0)))
	}
	res, ok = r.Get(1).(*http.Response)
	if !ok {
		panic(fmt.Sprintf("Couldn't typecast response object because it was a %t", r.Get(1)))
	}
	return req, res, r.Error(2)
}

func (c *Client) ReadDefinitions() (*lib.Definitions, error) {
	r := c.Called()
	defs, _ := r.Get(0).(*lib.Definitions)
	return defs, r.Error(1)
}

func (c *Client) AddIP(name *lib.VirtualMachineName, spec *brain.IPCreateRequest) (brain.IPs, error) {
	r := c.Called(name, spec)
	ips, _ := r.Get(0).(brain.IPs)
	return ips, r.Error(1)
}

func (c *Client) AddUserAuthorizedKey(name, key string) error {
	r := c.Called(name, key)
	return r.Error(0)
}

func (c *Client) DeleteUserAuthorizedKey(name, key string) error {
	r := c.Called(name, key)
	return r.Error(0)
}

func (c *Client) GetUser(name string) (*brain.User, error) {
	r := c.Called(name)
	u, _ := r.Get(0).(*brain.User)
	return u, r.Error(1)
}

func (c *Client) CreateCreditCard(cc *spp.CreditCard) (string, error) {
	r := c.Called(cc)
	return r.String(0), r.Error(1)
}
func (c *Client) CreateCreditCardWithToken(cc *spp.CreditCard, token string) (string, error) {
	r := c.Called(cc, token)
	return r.String(0), r.Error(1)
}
func (c *Client) CreateAccount(acc *lib.Account) (*lib.Account, error) {
	r := c.Called(acc)
	a, _ := r.Get(0).(*lib.Account)
	return a, r.Error(1)
}

func (c *Client) RegisterNewAccount(acc *lib.Account) (*lib.Account, error) {
	r := c.Called(acc)
	a, _ := r.Get(0).(*lib.Account)
	return a, r.Error(1)
}

func (c *Client) GetAccount(name string) (account *lib.Account, err error) {
	r := c.Called(name)
	acc, _ := r.Get(0).(*lib.Account)
	return acc, r.Error(1)
}

func (c *Client) GetDefaultAccount() (account *lib.Account, err error) {
	r := c.Called()
	acc, _ := r.Get(0).(*lib.Account)
	return acc, r.Error(1)
}

func (c *Client) GetAccounts() (accounts []*lib.Account, err error) {
	r := c.Called()
	acc, _ := r.Get(0).([]*lib.Account)
	return acc, r.Error(1)
}

func (c *Client) CreateDisc(name *lib.VirtualMachineName, disc brain.Disc) error {
	r := c.Called(name, disc)
	return r.Error(0)
}

func (c *Client) GetDisc(name *lib.VirtualMachineName, discId string) (disc *brain.Disc, err error) {
	r := c.Called(name, discId)
	disc, _ = r.Get(0).(*brain.Disc)
	return disc, r.Error(1)
}

func (c *Client) CreateGroup(name *lib.GroupName) error {
	r := c.Called(name)
	return r.Error(0)
}

func (c *Client) GetGroup(name *lib.GroupName) (*brain.Group, error) {
	r := c.Called(name)
	group, _ := r.Get(0).(*brain.Group)
	return group, r.Error(1)
}

func (c *Client) DeleteDisc(name *lib.VirtualMachineName, disc string) error {
	r := c.Called(name, disc)
	return r.Error(0)
}

func (c *Client) DeleteGroup(name *lib.GroupName) error {
	r := c.Called(name)
	return r.Error(0)
}

func (c *Client) DeleteVirtualMachine(name *lib.VirtualMachineName, purge bool) error {
	r := c.Called(name, purge)
	return r.Error(0)
}

func (c *Client) CreateVirtualMachine(group *lib.GroupName, vm brain.VirtualMachineSpec) (*brain.VirtualMachine, error) {
	r := c.Called(group, vm)
	rvm, _ := r.Get(0).(*brain.VirtualMachine)
	return rvm, r.Error(1)
}

func (c *Client) GetVirtualMachine(name *lib.VirtualMachineName) (vm *brain.VirtualMachine, err error) {
	r := c.Called(name)
	vm, _ = r.Get(0).(*brain.VirtualMachine)
	return vm, r.Error(1)
}

func (c *Client) MoveVirtualMachine(oldName *lib.VirtualMachineName, newName *lib.VirtualMachineName) error {
	r := c.Called(oldName, newName)
	return r.Error(0)
}

func (c *Client) ParseVirtualMachineName(name string, defaults ...*lib.VirtualMachineName) (*lib.VirtualMachineName, error) {
	r := c.Called(name, defaults)
	n, _ := r.Get(0).(*lib.VirtualMachineName)
	return n, r.Error(1)
}

func (c *Client) ParseGroupName(name string, defaults ...*lib.GroupName) *lib.GroupName {
	r := c.Called(name, defaults)
	n, _ := r.Get(0).(*lib.GroupName)
	return n
}

func (c *Client) ParseAccountName(name string, defaults ...string) string {
	r := c.Called(name, defaults)
	return r.String(0)
}

func (c *Client) ReimageVirtualMachine(name *lib.VirtualMachineName, image *brain.ImageInstall) error {
	r := c.Called(name, image)
	return r.Error(0)
}

func (c *Client) ResetVirtualMachine(name *lib.VirtualMachineName) error {
	r := c.Called(name)
	return r.Error(0)
}

func (c *Client) ResizeDisc(name *lib.VirtualMachineName, id string, size int) error {
	r := c.Called(name, id, size)
	return r.Error(0)
}

func (c *Client) SetDiscIopsLimit(name *lib.VirtualMachineName, id string, size int) error {
	r := c.Called(name, id, size)
	return r.Error(0)
}

func (c *Client) RestartVirtualMachine(name *lib.VirtualMachineName) error {
	r := c.Called(name)
	return r.Error(0)
}
func (c *Client) SetVirtualMachineCDROM(name *lib.VirtualMachineName, url string) error {
	r := c.Called(name, url)
	return r.Error(0)
}
func (c *Client) SetVirtualMachineCores(name *lib.VirtualMachineName, cores int) error {
	r := c.Called(name, cores)
	return r.Error(0)
}
func (c *Client) SetVirtualMachineHardwareProfile(name *lib.VirtualMachineName, hwprofile string, locked ...bool) error {
	r := c.Called(name, hwprofile, locked)
	return r.Error(0)
}
func (c *Client) SetVirtualMachineHardwareProfileLock(name *lib.VirtualMachineName, locked bool) error {
	r := c.Called(name, locked)
	return r.Error(0)
}
func (c *Client) SetVirtualMachineMemory(name *lib.VirtualMachineName, memory int) error {
	r := c.Called(name, memory)
	return r.Error(0)
}
func (c *Client) StartVirtualMachine(name *lib.VirtualMachineName) error {
	r := c.Called(name)
	return r.Error(0)
}
func (c *Client) StopVirtualMachine(name *lib.VirtualMachineName) error {
	r := c.Called(name)
	return r.Error(0)
}
func (c *Client) ShutdownVirtualMachine(name *lib.VirtualMachineName, stayoff bool) error {
	r := c.Called(name, stayoff)
	return r.Error(0)
}

func (c *Client) UndeleteVirtualMachine(name *lib.VirtualMachineName) error {
	r := c.Called(name)
	return r.Error(0)
}

func (c *Client) CreateBackup(server lib.VirtualMachineName, discLabelOrID string) (brain.Backup, error) {
	r := c.Called(server, discLabelOrID)
	snap, _ := r.Get(0).(brain.Backup)
	return snap, r.Error(1)
}
func (c *Client) DeleteBackup(server lib.VirtualMachineName, discLabelOrID string, backupLabelOrID string) error {
	r := c.Called(server, discLabelOrID, backupLabelOrID)
	return r.Error(0)
}
func (c *Client) CreateBackupSchedule(server lib.VirtualMachineName, discLabelOrID string, start string, interval int) (brain.BackupSchedule, error) {
	r := c.Called(server, discLabelOrID, start, interval)
	sched, _ := r.Get(0).(brain.BackupSchedule)
	return sched, r.Error(1)
}
func (c *Client) DeleteBackupSchedule(server lib.VirtualMachineName, discLabelOrID string, id int) error {
	r := c.Called(server, discLabelOrID, id)
	return r.Error(0)
}
func (c *Client) GetBackups(server lib.VirtualMachineName, discLabelOrID string) (brain.Backups, error) {
	r := c.Called(server, discLabelOrID)
	snaps, _ := r.Get(0).(brain.Backups)
	return snaps, r.Error(1)
}
func (c *Client) RestoreBackup(server lib.VirtualMachineName, discLabelOrID string, backupLabelOrID string) (brain.Backup, error) {
	r := c.Called(server, discLabelOrID, backupLabelOrID)
	snap, _ := r.Get(0).(brain.Backup)

	return snap, r.Error(1)
}

func (c *Client) GetPrivileges(username string) (privs brain.Privileges, err error) {
	r := c.Called(username)
	privs, _ = r.Get(0).(brain.Privileges)
	return privs, r.Error(1)
}
func (c *Client) GetPrivilegesForAccount(accountName string) (privs brain.Privileges, err error) {
	r := c.Called(accountName)
	privs, _ = r.Get(0).(brain.Privileges)
	return privs, r.Error(1)
}
func (c *Client) GetPrivilegesForGroup(group lib.GroupName) (privs brain.Privileges, err error) {
	r := c.Called(group)
	privs, _ = r.Get(0).(brain.Privileges)
	return privs, r.Error(1)
}
func (c *Client) GetPrivilegesForVirtualMachine(vm lib.VirtualMachineName) (privs brain.Privileges, err error) {
	r := c.Called(vm)
	privs, _ = r.Get(0).(brain.Privileges)
	return privs, r.Error(1)
}
func (c *Client) GrantPrivilege(priv brain.Privilege) (err error) {
	r := c.Called(priv)
	return r.Error(0)
}
func (c *Client) RevokePrivilege(priv brain.Privilege) (err error) {
	r := c.Called(priv)
	return r.Error(0)
}
<commit_msg>Fix tests so mock matches the interface<commit_after>package mocks

import (
	"fmt"
	auth3 "github.com/BytemarkHosting/auth-client"
	"github.com/BytemarkHosting/bytemark-client/lib"
	"github.com/BytemarkHosting/bytemark-client/lib/billing"
	"github.com/BytemarkHosting/bytemark-client/lib/brain"
	"github.com/BytemarkHosting/bytemark-client/lib/spp"
	mock "github.com/maraino/go-mock"
	"net/http"
	"net/url"
)

type Client struct {
	mock.Mock
}

func (c *Client) AllowInsecureRequests() {
	c.Called()
}
func (c *Client) BuildRequestNoAuth(method string, endpoint lib.Endpoint, path string, parts ...string) (*lib.Request, error) {
	r := c.Called(method, endpoint, path, parts)
	req, _ := r.Get(0).(*lib.Request)
	return req, r.Error(1)
}
func (c *Client) BuildRequest(method string, endpoint lib.Endpoint, path string, parts ...string) (*lib.Request, error) {
	r := c.Called(method, endpoint, path, parts)
	req, _ := r.Get(0).(*lib.Request)
	return req, r.Error(1)

}
func (c *Client) NewRequestNoAuth(method string, url *url.URL) *lib.Request {
	r := c.Called(method, url)
	req, _ := r.Get(0).(*lib.Request)
	return req
}
func (c *Client) NewRequest(method string, url *url.URL) *lib.Request {
	r := c.Called(method, url)
	req, _ := r.Get(0).(*lib.Request)
	return req
}

func (c *Client) GetEndpoint() string {
	r := c.Called()
	return r.String(0)
}
func (c *Client) GetSessionToken() string {
	r := c.Called()
	return r.String(0)
}
func (c *Client) GetSessionUser() string {
	r := c.Called()
	return r.String(0)
}
func (c *Client) GetSessionFactors() []string {
	r := c.Called()
	ar := r.Get(0)
	return ar.([]string)
}
func (c *Client) GetSPPToken(cc spp.CreditCard, owner *billing.Person) (string, error) {
	r := c.Called(cc, owner)
	return r.String(0), r.Error(1)
}
func (c *Client) SetDebugLevel(level int) {
	c.Called(level)
}
func (c *Client) AuthWithToken(token string) error {
	r := c.Called(token)
	return r.Error(0)
}
func (c *Client) AuthWithCredentials(credents auth3.Credentials) error {
	r := c.Called(credents)
	return r.Error(0)
}
func (c *Client) RequestAndUnmarshal(auth bool, method, path, requestBody string, output interface{}) error {
	r := c.Called(auth, method, path, requestBody, output)
	return r.Error(0)
}
func (c *Client) RequestAndRead(auth bool, method, path, requestBody string) (responseBody []byte, err error) {
	r := c.Called(auth, method, path, requestBody)
	return r.Bytes(0), r.Error(1)
}

func (c *Client) Request(auth bool, method string, location string, requestBody string) (req *http.Request, res *http.Response, err error) {
	r := c.Called(auth, method, location, requestBody)
	req, ok := r.Get(0).(*http.Request)
	if !ok {
		panic(fmt.Sprintf("Couldn't typecast request object because it was a %t", r.Get(0)))
	}
	res, ok = r.Get(1).(*http.Response)
	if !ok {
		panic(fmt.Sprintf("Couldn't typecast response object because it was a %t", r.Get(1)))
	}
	return req, res, r.Error(2)
}

func (c *Client) ReadDefinitions() (*lib.Definitions, error) {
	r := c.Called()
	defs, _ := r.Get(0).(*lib.Definitions)
	return defs, r.Error(1)
}

func (c *Client) AddIP(name *lib.VirtualMachineName, spec *brain.IPCreateRequest) (brain.IPs, error) {
	r := c.Called(name, spec)
	ips, _ := r.Get(0).(brain.IPs)
	return ips, r.Error(1)
}

func (c *Client) AddUserAuthorizedKey(name, key string) error {
	r := c.Called(name, key)
	return r.Error(0)
}

func (c *Client) DeleteUserAuthorizedKey(name, key string) error {
	r := c.Called(name, key)
	return r.Error(0)
}

func (c *Client) GetUser(name string) (*brain.User, error) {
	r := c.Called(name)
	u, _ := r.Get(0).(*brain.User)
	return u, r.Error(1)
}

func (c *Client) CreateCreditCard(cc *spp.CreditCard) (string, error) {
	r := c.Called(cc)
	return r.String(0), r.Error(1)
}
func (c *Client) CreateCreditCardWithToken(cc *spp.CreditCard, token string) (string, error) {
	r := c.Called(cc, token)
	return r.String(0), r.Error(1)
}
func (c *Client) CreateAccount(acc *lib.Account) (*lib.Account, error) {
	r := c.Called(acc)
	a, _ := r.Get(0).(*lib.Account)
	return a, r.Error(1)
}

func (c *Client) RegisterNewAccount(acc *lib.Account) (*lib.Account, error) {
	r := c.Called(acc)
	a, _ := r.Get(0).(*lib.Account)
	return a, r.Error(1)
}

func (c *Client) GetAccount(name string) (account *lib.Account, err error) {
	r := c.Called(name)
	acc, _ := r.Get(0).(*lib.Account)
	return acc, r.Error(1)
}

func (c *Client) GetDefaultAccount() (account *lib.Account, err error) {
	r := c.Called()
	acc, _ := r.Get(0).(*lib.Account)
	return acc, r.Error(1)
}

func (c *Client) GetAccounts() (accounts []*lib.Account, err error) {
	r := c.Called()
	acc, _ := r.Get(0).([]*lib.Account)
	return acc, r.Error(1)
}

func (c *Client) CreateDisc(name *lib.VirtualMachineName, disc brain.Disc) error {
	r := c.Called(name, disc)
	return r.Error(0)
}

func (c *Client) GetDisc(name *lib.VirtualMachineName, discId string) (disc *brain.Disc, err error) {
	r := c.Called(name, discId)
	disc, _ = r.Get(0).(*brain.Disc)
	return disc, r.Error(1)
}

func (c *Client) CreateGroup(name *lib.GroupName) error {
	r := c.Called(name)
	return r.Error(0)
}

func (c *Client) GetGroup(name *lib.GroupName) (*brain.Group, error) {
	r := c.Called(name)
	group, _ := r.Get(0).(*brain.Group)
	return group, r.Error(1)
}

func (c *Client) DeleteDisc(name *lib.VirtualMachineName, disc string) error {
	r := c.Called(name, disc)
	return r.Error(0)
}

func (c *Client) DeleteGroup(name *lib.GroupName) error {
	r := c.Called(name)
	return r.Error(0)
}

func (c *Client) DeleteVirtualMachine(name *lib.VirtualMachineName, purge bool) error {
	r := c.Called(name, purge)
	return r.Error(0)
}

func (c *Client) CreateVirtualMachine(group *lib.GroupName, vm brain.VirtualMachineSpec) (*brain.VirtualMachine, error) {
	r := c.Called(group, vm)
	rvm, _ := r.Get(0).(*brain.VirtualMachine)
	return rvm, r.Error(1)
}

func (c *Client) GetVirtualMachine(name *lib.VirtualMachineName) (vm *brain.VirtualMachine, err error) {
	r := c.Called(name)
	vm, _ = r.Get(0).(*brain.VirtualMachine)
	return vm, r.Error(1)
}

func (c *Client) MoveVirtualMachine(oldName *lib.VirtualMachineName, newName *lib.VirtualMachineName) error {
	r := c.Called(oldName, newName)
	return r.Error(0)
}

func (c *Client) ParseVirtualMachineName(name string, defaults ...*lib.VirtualMachineName) (*lib.VirtualMachineName, error) {
	r := c.Called(name, defaults)
	n, _ := r.Get(0).(*lib.VirtualMachineName)
	return n, r.Error(1)
}

func (c *Client) ParseGroupName(name string, defaults ...*lib.GroupName) *lib.GroupName {
	r := c.Called(name, defaults)
	n, _ := r.Get(0).(*lib.GroupName)
	return n
}

func (c *Client) ParseAccountName(name string, defaults ...string) string {
	r := c.Called(name, defaults)
	return r.String(0)
}

func (c *Client) ReimageVirtualMachine(name *lib.VirtualMachineName, image *brain.ImageInstall) error {
	r := c.Called(name, image)
	return r.Error(0)
}

func (c *Client) ResetVirtualMachine(name *lib.VirtualMachineName) error {
	r := c.Called(name)
	return r.Error(0)
}

func (c *Client) ResizeDisc(name *lib.VirtualMachineName, id string, size int) error {
	r := c.Called(name, id, size)
	return r.Error(0)
}

func (c *Client) SetDiscIopsLimit(name *lib.VirtualMachineName, id string, size int) error {
	r := c.Called(name, id, size)
	return r.Error(0)
}

func (c *Client) RestartVirtualMachine(name *lib.VirtualMachineName) error {
	r := c.Called(name)
	return r.Error(0)
}
func (c *Client) SetVirtualMachineCDROM(name *lib.VirtualMachineName, url string) error {
	r := c.Called(name, url)
	return r.Error(0)
}
func (c *Client) SetVirtualMachineCores(name *lib.VirtualMachineName, cores int) error {
	r := c.Called(name, cores)
	return r.Error(0)
}
func (c *Client) SetVirtualMachineHardwareProfile(name *lib.VirtualMachineName, hwprofile string, locked ...bool) error {
	r := c.Called(name, hwprofile, locked)
	return r.Error(0)
}
func (c *Client) SetVirtualMachineHardwareProfileLock(name *lib.VirtualMachineName, locked bool) error {
	r := c.Called(name, locked)
	return r.Error(0)
}
func (c *Client) SetVirtualMachineMemory(name *lib.VirtualMachineName, memory int) error {
	r := c.Called(name, memory)
	return r.Error(0)
}
func (c *Client) StartVirtualMachine(name *lib.VirtualMachineName) error {
	r := c.Called(name)
	return r.Error(0)
}
func (c *Client) StopVirtualMachine(name *lib.VirtualMachineName) error {
	r := c.Called(name)
	return r.Error(0)
}
func (c *Client) ShutdownVirtualMachine(name *lib.VirtualMachineName, stayoff bool) error {
	r := c.Called(name, stayoff)
	return r.Error(0)
}

func (c *Client) UndeleteVirtualMachine(name *lib.VirtualMachineName) error {
	r := c.Called(name)
	return r.Error(0)
}

func (c *Client) CreateBackup(server lib.VirtualMachineName, discLabelOrID string) (brain.Backup, error) {
	r := c.Called(server, discLabelOrID)
	snap, _ := r.Get(0).(brain.Backup)
	return snap, r.Error(1)
}
func (c *Client) DeleteBackup(server lib.VirtualMachineName, discLabelOrID string, backupLabelOrID string) error {
	r := c.Called(server, discLabelOrID, backupLabelOrID)
	return r.Error(0)
}
func (c *Client) CreateBackupSchedule(server lib.VirtualMachineName, discLabelOrID string, start string, interval int) (brain.BackupSchedule, error) {
	r := c.Called(server, discLabelOrID, start, interval)
	sched, _ := r.Get(0).(brain.BackupSchedule)
	return sched, r.Error(1)
}
func (c *Client) DeleteBackupSchedule(server lib.VirtualMachineName, discLabelOrID string, id int) error {
	r := c.Called(server, discLabelOrID, id)
	return r.Error(0)
}
func (c *Client) GetBackups(server lib.VirtualMachineName, discLabelOrID string) (brain.Backups, error) {
	r := c.Called(server, discLabelOrID)
	snaps, _ := r.Get(0).(brain.Backups)
	return snaps, r.Error(1)
}
func (c *Client) RestoreBackup(server lib.VirtualMachineName, discLabelOrID string, backupLabelOrID string) (brain.Backup, error) {
	r := c.Called(server, discLabelOrID, backupLabelOrID)
	snap, _ := r.Get(0).(brain.Backup)

	return snap, r.Error(1)
}

func (c *Client) GetPrivileges(username string) (privs brain.Privileges, err error) {
	r := c.Called(username)
	privs, _ = r.Get(0).(brain.Privileges)
	return privs, r.Error(1)
}
func (c *Client) GetPrivilegesForAccount(accountName string) (privs brain.Privileges, err error) {
	r := c.Called(accountName)
	privs, _ = r.Get(0).(brain.Privileges)
	return privs, r.Error(1)
}
func (c *Client) GetPrivilegesForGroup(group lib.GroupName) (privs brain.Privileges, err error) {
	r := c.Called(group)
	privs, _ = r.Get(0).(brain.Privileges)
	return privs, r.Error(1)
}
func (c *Client) GetPrivilegesForVirtualMachine(vm lib.VirtualMachineName) (privs brain.Privileges, err error) {
	r := c.Called(vm)
	privs, _ = r.Get(0).(brain.Privileges)
	return privs, r.Error(1)
}
func (c *Client) GrantPrivilege(priv brain.Privilege) (err error) {
	r := c.Called(priv)
	return r.Error(0)
}
func (c *Client) RevokePrivilege(priv brain.Privilege) (err error) {
	r := c.Called(priv)
	return r.Error(0)
}
func (c *Client) GetVLANs() ([]*brain.VLAN, error) {
	r := c.Called()
	vlans, _ := r.Get(0).([]*brain.VLAN)
	return vlans, r.Error(1)
}
<|endoftext|>


<commit_before>package parser

import(
	tp "tritium/proto"
	. "exec"
	"log"
	proto "goprotobuf.googlecode.com/hg/proto"
)

func ParseFile(file string) (*tp.ScriptObject) {
	cmd := Command("../../../bin/ts2to", file)
	data, err := cmd.CombinedOutput()
	if err != nil {
		log.Fatal("ts2to failed with message:", err.String(), "\n", string(data))
	}
	obj := &tp.ScriptObject{}
	err = proto.Unmarshal(data, obj)
	if err != nil {
		log.Fatal(err)
	}
	obj.Imports()
	return obj
}

//func ParseFileSet(mainFile string) ([]*tp.ScriptObject) {

//}<commit_msg>Parsing all imported files<commit_after>package parser

import(
	tp "tritium/proto"
	. "exec"
	"log"
	proto "goprotobuf.googlecode.com/hg/proto"
)

func ParseFile(file string) (*tp.ScriptObject) {
	cmd := Command("../../../bin/ts2to", file)
	data, err := cmd.CombinedOutput()
	if err != nil {
		log.Fatal("ts2to failed with message:", err.String(), "\n", string(data))
	}
	obj := &tp.ScriptObject{}
	err = proto.Unmarshal(data, obj)
	if err != nil {
		log.Fatal(err)
	}
	obj.Imports()
	return obj
}

func ParseFileSet(file string) ([]*tp.ScriptObject) {
	objs := make([]*tp.ScriptObject, 0)
	files := make(map[string]int)
	objs = append(objs, ParseFile(file))
	files[file] = 1
	for _, obj := range(objs) {
		for _, importFile := range(obj.Imports()) {
			if(files[importFile] == 0) {
				println("must import ", importFile)
			}
		}
	}

	return objs
}<|endoftext|>


<commit_before>// Copyright 2021 The Ebiten Authors
//
// 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 opengl

import (
	"syscall/js"
)

type gl struct {
	activeTexture            js.Value
	attachShader             js.Value
	bindAttribLocation       js.Value
	bindBuffer               js.Value
	bindFramebuffer          js.Value
	bindRenderbuffer         js.Value
	bindTexture              js.Value
	blendFunc                js.Value
	bufferData               js.Value
	bufferSubData            js.Value
	checkFramebufferStatus   js.Value
	clear                    js.Value
	colorMask                js.Value
	compileShader            js.Value
	createBuffer             js.Value
	createFramebuffer        js.Value
	createProgram            js.Value
	createRenderbuffer       js.Value
	createShader             js.Value
	createTexture            js.Value
	deleteBuffer             js.Value
	deleteFramebuffer        js.Value
	deleteProgram            js.Value
	deleteRenderbuffer       js.Value
	deleteShader             js.Value
	deleteTexture            js.Value
	disable                  js.Value
	disableVertexAttribArray js.Value
	drawElements             js.Value
	enable                   js.Value
	enableVertexAttribArray  js.Value
	framebufferRenderbuffer  js.Value
	framebufferTexture2D     js.Value
	flush                    js.Value
	getBufferSubData         js.Value
	getExtension             js.Value
	getParameter             js.Value
	getProgramInfoLog        js.Value
	getProgramParameter      js.Value
	getShaderInfoLog         js.Value
	getShaderParameter       js.Value
	getShaderPrecisionFormat js.Value
	getUniformLocation       js.Value
	isContextLost            js.Value
	isFramebuffer            js.Value
	isProgram                js.Value
	isRenderbuffer           js.Value
	isTexture                js.Value
	linkProgram              js.Value
	pixelStorei              js.Value
	readPixels               js.Value
	renderbufferStorage      js.Value
	scissor                  js.Value
	shaderSource             js.Value
	stencilFunc              js.Value
	stencilMask              js.Value
	stencilOp                js.Value
	texImage2D               js.Value
	texSubImage2D            js.Value
	texParameteri            js.Value
	uniform1f                js.Value
	uniform1fv               js.Value
	uniform2fv               js.Value
	uniform3fv               js.Value
	uniform4fv               js.Value
	uniform1i                js.Value
	uniformMatrix2fv         js.Value
	uniformMatrix3fv         js.Value
	uniformMatrix4fv         js.Value
	useProgram               js.Value
	vertexAttribPointer      js.Value
	viewport                 js.Value
}

func (c *context) newGL(v js.Value) *gl {
	// Passing a Go string to the JS world is expensive. This causes conversion to UTF-16 (#1438).
	// In order to reduce the cost when calling functions, create the function objects by bind and use them.
	g := &gl{
		activeTexture:            v.Get("activeTexture").Call("bind", v),
		attachShader:             v.Get("attachShader").Call("bind", v),
		bindAttribLocation:       v.Get("bindAttribLocation").Call("bind", v),
		bindBuffer:               v.Get("bindBuffer").Call("bind", v),
		bindFramebuffer:          v.Get("bindFramebuffer").Call("bind", v),
		bindRenderbuffer:         v.Get("bindRenderbuffer").Call("bind", v),
		bindTexture:              v.Get("bindTexture").Call("bind", v),
		blendFunc:                v.Get("blendFunc").Call("bind", v),
		bufferData:               v.Get("bufferData").Call("bind", v),
		bufferSubData:            v.Get("bufferSubData").Call("bind", v),
		checkFramebufferStatus:   v.Get("checkFramebufferStatus").Call("bind", v),
		clear:                    v.Get("clear").Call("bind", v),
		colorMask:                v.Get("colorMask").Call("bind", v),
		compileShader:            v.Get("compileShader").Call("bind", v),
		createBuffer:             v.Get("createBuffer").Call("bind", v),
		createFramebuffer:        v.Get("createFramebuffer").Call("bind", v),
		createProgram:            v.Get("createProgram").Call("bind", v),
		createRenderbuffer:       v.Get("createRenderbuffer").Call("bind", v),
		createShader:             v.Get("createShader").Call("bind", v),
		createTexture:            v.Get("createTexture").Call("bind", v),
		deleteBuffer:             v.Get("deleteBuffer").Call("bind", v),
		deleteFramebuffer:        v.Get("deleteFramebuffer").Call("bind", v),
		deleteProgram:            v.Get("deleteProgram").Call("bind", v),
		deleteRenderbuffer:       v.Get("deleteRenderbuffer").Call("bind", v),
		deleteShader:             v.Get("deleteShader").Call("bind", v),
		deleteTexture:            v.Get("deleteTexture").Call("bind", v),
		disable:                  v.Get("disable").Call("bind", v),
		disableVertexAttribArray: v.Get("disableVertexAttribArray").Call("bind", v),
		drawElements:             v.Get("drawElements").Call("bind", v),
		enable:                   v.Get("enable").Call("bind", v),
		enableVertexAttribArray:  v.Get("enableVertexAttribArray").Call("bind", v),
		framebufferRenderbuffer:  v.Get("framebufferRenderbuffer").Call("bind", v),
		framebufferTexture2D:     v.Get("framebufferTexture2D").Call("bind", v),
		flush:                    v.Get("flush").Call("bind", v),
		getParameter:             v.Get("getParameter").Call("bind", v),
		getProgramInfoLog:        v.Get("getProgramInfoLog").Call("bind", v),
		getProgramParameter:      v.Get("getProgramParameter").Call("bind", v),
		getShaderInfoLog:         v.Get("getShaderInfoLog").Call("bind", v),
		getShaderParameter:       v.Get("getShaderParameter").Call("bind", v),
		getShaderPrecisionFormat: v.Get("getShaderPrecisionFormat").Call("bind", v),
		getUniformLocation:       v.Get("getUniformLocation").Call("bind", v),
		isContextLost:            v.Get("isContextLost").Call("bind", v),
		isFramebuffer:            v.Get("isFramebuffer").Call("bind", v),
		isProgram:                v.Get("isProgram").Call("bind", v),
		isRenderbuffer:           v.Get("isRenderbuffer").Call("bind", v),
		isTexture:                v.Get("isTexture").Call("bind", v),
		linkProgram:              v.Get("linkProgram").Call("bind", v),
		pixelStorei:              v.Get("pixelStorei").Call("bind", v),
		readPixels:               v.Get("readPixels").Call("bind", v),
		renderbufferStorage:      v.Get("renderbufferStorage").Call("bind", v),
		scissor:                  v.Get("scissor").Call("bind", v),
		shaderSource:             v.Get("shaderSource").Call("bind", v),
		stencilFunc:              v.Get("stencilFunc").Call("bind", v),
		stencilMask:              v.Get("stencilMask").Call("bind", v),
		stencilOp:                v.Get("stencilOp").Call("bind", v),
		texImage2D:               v.Get("texImage2D").Call("bind", v),
		texSubImage2D:            v.Get("texSubImage2D").Call("bind", v),
		texParameteri:            v.Get("texParameteri").Call("bind", v),
		uniform1f:                v.Get("uniform1f").Call("bind", v),
		uniform1fv:               v.Get("uniform1fv").Call("bind", v),
		uniform2fv:               v.Get("uniform2fv").Call("bind", v),
		uniform3fv:               v.Get("uniform3fv").Call("bind", v),
		uniform4fv:               v.Get("uniform4fv").Call("bind", v),
		uniform1i:                v.Get("uniform1i").Call("bind", v),
		uniformMatrix2fv:         v.Get("uniformMatrix2fv").Call("bind", v),
		uniformMatrix3fv:         v.Get("uniformMatrix3fv").Call("bind", v),
		uniformMatrix4fv:         v.Get("uniformMatrix4fv").Call("bind", v),
		useProgram:               v.Get("useProgram").Call("bind", v),
		vertexAttribPointer:      v.Get("vertexAttribPointer").Call("bind", v),
		viewport:                 v.Get("viewport").Call("bind", v),
	}
	if c.usesWebGL2() {
		g.getExtension = v.Get("getBufferSubData").Call("bind", v)
	} else {
		g.getExtension = v.Get("getExtension").Call("bind", v)
	}
	return g
}
<commit_msg>internal/graphicsdriver/opengl: remove an unused member gl.getBufferSubData<commit_after>// Copyright 2021 The Ebiten Authors
//
// 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 opengl

import (
	"syscall/js"
)

type gl struct {
	activeTexture            js.Value
	attachShader             js.Value
	bindAttribLocation       js.Value
	bindBuffer               js.Value
	bindFramebuffer          js.Value
	bindRenderbuffer         js.Value
	bindTexture              js.Value
	blendFunc                js.Value
	bufferData               js.Value
	bufferSubData            js.Value
	checkFramebufferStatus   js.Value
	clear                    js.Value
	colorMask                js.Value
	compileShader            js.Value
	createBuffer             js.Value
	createFramebuffer        js.Value
	createProgram            js.Value
	createRenderbuffer       js.Value
	createShader             js.Value
	createTexture            js.Value
	deleteBuffer             js.Value
	deleteFramebuffer        js.Value
	deleteProgram            js.Value
	deleteRenderbuffer       js.Value
	deleteShader             js.Value
	deleteTexture            js.Value
	disable                  js.Value
	disableVertexAttribArray js.Value
	drawElements             js.Value
	enable                   js.Value
	enableVertexAttribArray  js.Value
	framebufferRenderbuffer  js.Value
	framebufferTexture2D     js.Value
	flush                    js.Value
	getExtension             js.Value
	getParameter             js.Value
	getProgramInfoLog        js.Value
	getProgramParameter      js.Value
	getShaderInfoLog         js.Value
	getShaderParameter       js.Value
	getShaderPrecisionFormat js.Value
	getUniformLocation       js.Value
	isContextLost            js.Value
	isFramebuffer            js.Value
	isProgram                js.Value
	isRenderbuffer           js.Value
	isTexture                js.Value
	linkProgram              js.Value
	pixelStorei              js.Value
	readPixels               js.Value
	renderbufferStorage      js.Value
	scissor                  js.Value
	shaderSource             js.Value
	stencilFunc              js.Value
	stencilMask              js.Value
	stencilOp                js.Value
	texImage2D               js.Value
	texSubImage2D            js.Value
	texParameteri            js.Value
	uniform1f                js.Value
	uniform1fv               js.Value
	uniform2fv               js.Value
	uniform3fv               js.Value
	uniform4fv               js.Value
	uniform1i                js.Value
	uniformMatrix2fv         js.Value
	uniformMatrix3fv         js.Value
	uniformMatrix4fv         js.Value
	useProgram               js.Value
	vertexAttribPointer      js.Value
	viewport                 js.Value
}

func (c *context) newGL(v js.Value) *gl {
	// Passing a Go string to the JS world is expensive. This causes conversion to UTF-16 (#1438).
	// In order to reduce the cost when calling functions, create the function objects by bind and use them.
	g := &gl{
		activeTexture:            v.Get("activeTexture").Call("bind", v),
		attachShader:             v.Get("attachShader").Call("bind", v),
		bindAttribLocation:       v.Get("bindAttribLocation").Call("bind", v),
		bindBuffer:               v.Get("bindBuffer").Call("bind", v),
		bindFramebuffer:          v.Get("bindFramebuffer").Call("bind", v),
		bindRenderbuffer:         v.Get("bindRenderbuffer").Call("bind", v),
		bindTexture:              v.Get("bindTexture").Call("bind", v),
		blendFunc:                v.Get("blendFunc").Call("bind", v),
		bufferData:               v.Get("bufferData").Call("bind", v),
		bufferSubData:            v.Get("bufferSubData").Call("bind", v),
		checkFramebufferStatus:   v.Get("checkFramebufferStatus").Call("bind", v),
		clear:                    v.Get("clear").Call("bind", v),
		colorMask:                v.Get("colorMask").Call("bind", v),
		compileShader:            v.Get("compileShader").Call("bind", v),
		createBuffer:             v.Get("createBuffer").Call("bind", v),
		createFramebuffer:        v.Get("createFramebuffer").Call("bind", v),
		createProgram:            v.Get("createProgram").Call("bind", v),
		createRenderbuffer:       v.Get("createRenderbuffer").Call("bind", v),
		createShader:             v.Get("createShader").Call("bind", v),
		createTexture:            v.Get("createTexture").Call("bind", v),
		deleteBuffer:             v.Get("deleteBuffer").Call("bind", v),
		deleteFramebuffer:        v.Get("deleteFramebuffer").Call("bind", v),
		deleteProgram:            v.Get("deleteProgram").Call("bind", v),
		deleteRenderbuffer:       v.Get("deleteRenderbuffer").Call("bind", v),
		deleteShader:             v.Get("deleteShader").Call("bind", v),
		deleteTexture:            v.Get("deleteTexture").Call("bind", v),
		disable:                  v.Get("disable").Call("bind", v),
		disableVertexAttribArray: v.Get("disableVertexAttribArray").Call("bind", v),
		drawElements:             v.Get("drawElements").Call("bind", v),
		enable:                   v.Get("enable").Call("bind", v),
		enableVertexAttribArray:  v.Get("enableVertexAttribArray").Call("bind", v),
		framebufferRenderbuffer:  v.Get("framebufferRenderbuffer").Call("bind", v),
		framebufferTexture2D:     v.Get("framebufferTexture2D").Call("bind", v),
		flush:                    v.Get("flush").Call("bind", v),
		getParameter:             v.Get("getParameter").Call("bind", v),
		getProgramInfoLog:        v.Get("getProgramInfoLog").Call("bind", v),
		getProgramParameter:      v.Get("getProgramParameter").Call("bind", v),
		getShaderInfoLog:         v.Get("getShaderInfoLog").Call("bind", v),
		getShaderParameter:       v.Get("getShaderParameter").Call("bind", v),
		getShaderPrecisionFormat: v.Get("getShaderPrecisionFormat").Call("bind", v),
		getUniformLocation:       v.Get("getUniformLocation").Call("bind", v),
		isContextLost:            v.Get("isContextLost").Call("bind", v),
		isFramebuffer:            v.Get("isFramebuffer").Call("bind", v),
		isProgram:                v.Get("isProgram").Call("bind", v),
		isRenderbuffer:           v.Get("isRenderbuffer").Call("bind", v),
		isTexture:                v.Get("isTexture").Call("bind", v),
		linkProgram:              v.Get("linkProgram").Call("bind", v),
		pixelStorei:              v.Get("pixelStorei").Call("bind", v),
		readPixels:               v.Get("readPixels").Call("bind", v),
		renderbufferStorage:      v.Get("renderbufferStorage").Call("bind", v),
		scissor:                  v.Get("scissor").Call("bind", v),
		shaderSource:             v.Get("shaderSource").Call("bind", v),
		stencilFunc:              v.Get("stencilFunc").Call("bind", v),
		stencilMask:              v.Get("stencilMask").Call("bind", v),
		stencilOp:                v.Get("stencilOp").Call("bind", v),
		texImage2D:               v.Get("texImage2D").Call("bind", v),
		texSubImage2D:            v.Get("texSubImage2D").Call("bind", v),
		texParameteri:            v.Get("texParameteri").Call("bind", v),
		uniform1f:                v.Get("uniform1f").Call("bind", v),
		uniform1fv:               v.Get("uniform1fv").Call("bind", v),
		uniform2fv:               v.Get("uniform2fv").Call("bind", v),
		uniform3fv:               v.Get("uniform3fv").Call("bind", v),
		uniform4fv:               v.Get("uniform4fv").Call("bind", v),
		uniform1i:                v.Get("uniform1i").Call("bind", v),
		uniformMatrix2fv:         v.Get("uniformMatrix2fv").Call("bind", v),
		uniformMatrix3fv:         v.Get("uniformMatrix3fv").Call("bind", v),
		uniformMatrix4fv:         v.Get("uniformMatrix4fv").Call("bind", v),
		useProgram:               v.Get("useProgram").Call("bind", v),
		vertexAttribPointer:      v.Get("vertexAttribPointer").Call("bind", v),
		viewport:                 v.Get("viewport").Call("bind", v),
	}
	if !c.usesWebGL2() {
		g.getExtension = v.Get("getExtension").Call("bind", v)
	}
	return g
}
<|endoftext|>


<commit_before><commit_msg>read: Port support; fix Fun/NewFun return values<commit_after><|endoftext|>


<commit_before><commit_msg>more intuitive naming, switched to byte slices<commit_after><|endoftext|>