mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-31 23:37:01 +00:00
Merge pull request #589 from monnand/update-docker-client
update github.com/fsouza/go-dockerclient
This commit is contained in:
commit
65575953c0
@ -239,7 +239,7 @@ func (kl *Kubelet) runContainer(pod *Pod, container *api.Container, podVolumes v
|
||||
ExposedPorts: exposedPorts,
|
||||
Hostname: container.Name,
|
||||
Image: container.Image,
|
||||
Memory: int64(container.Memory),
|
||||
Memory: uint64(container.Memory),
|
||||
CpuShares: int64(milliCPUToShares(container.CPU)),
|
||||
Volumes: volumes,
|
||||
WorkingDir: container.WorkingDir,
|
||||
|
@ -2,6 +2,7 @@ language: go
|
||||
go:
|
||||
- 1.1.2
|
||||
- 1.2
|
||||
- 1.3
|
||||
- tip
|
||||
env:
|
||||
- GOARCH=amd64
|
||||
|
@ -10,6 +10,7 @@ Ed <edrocksit@gmail.com>
|
||||
Eric Anderson <anderson@copperegg.com>
|
||||
Flavia Missi <flaviamissi@gmail.com>
|
||||
Francisco Souza <f@souza.cc>
|
||||
Jari Kolehmainen <jari.kolehmainen@digia.com>
|
||||
Jason Wilder <jwilder@litl.com>
|
||||
Jean-Baptiste Dalido <jeanbaptiste@appgratis.com>
|
||||
Jeff Mitchell <jeffrey.mitchell@gmail.com>
|
||||
@ -19,6 +20,7 @@ Omeid Matten <public@omeid.me>
|
||||
Paul Morie <pmorie@gmail.com>
|
||||
Peter Jihoon Kim <raingrove@gmail.com>
|
||||
Philippe Lafoucrière <philippe.lafoucriere@tech-angels.com>
|
||||
Rafe Colton <r.colton@modcloth.com>
|
||||
Salvador Gironès <salvadorgirones@gmail.com>
|
||||
Simon Eskildsen <sirup@sirupsen.com>
|
||||
Simon Menke <simon.menke@gmail.com>
|
||||
|
@ -9,12 +9,6 @@ This package presents a client for the Docker remote API.
|
||||
|
||||
For more details, check the [remote API documentation](http://docs.docker.io/en/latest/reference/api/docker_remote_api/).
|
||||
|
||||
##Versioning
|
||||
|
||||
* Version 0.1 is compatible with Docker v0.7.1
|
||||
* The master is compatible with Docker's master
|
||||
|
||||
|
||||
## Example
|
||||
|
||||
package main
|
||||
|
@ -47,20 +47,17 @@ type ApiVersion []int
|
||||
// <minor> and <patch> are integer numbers.
|
||||
func NewApiVersion(input string) (ApiVersion, error) {
|
||||
if !strings.Contains(input, ".") {
|
||||
return nil, fmt.Errorf("Unable to parse version '%s'", input)
|
||||
return nil, fmt.Errorf("Unable to parse version %q", input)
|
||||
}
|
||||
|
||||
arr := strings.Split(input, ".")
|
||||
ret := make(ApiVersion, len(arr))
|
||||
|
||||
var err error
|
||||
for i, val := range arr {
|
||||
ret[i], err = strconv.Atoi(val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("Unable to parse version %q: %q is not an integer", input, val)
|
||||
}
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
@ -203,6 +200,21 @@ func parseApiVersionString(input string) (version uint16, err error) {
|
||||
return version, nil
|
||||
}
|
||||
|
||||
// Ping pings the docker server
|
||||
//
|
||||
// See http://goo.gl/stJENm for more details.
|
||||
func (c *Client) Ping() error {
|
||||
path := "/_ping"
|
||||
body, status, err := c.do("GET", path, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if status != http.StatusOK {
|
||||
return newError(status, body)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) getServerApiVersionString() (version string, err error) {
|
||||
body, status, err := c.do("GET", "/version", nil)
|
||||
if err != nil {
|
||||
@ -257,6 +269,7 @@ func (c *Client) do(method, path string, data interface{}) ([]byte, int, error)
|
||||
if err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
defer dial.Close()
|
||||
clientconn := httputil.NewClientConn(dial, nil)
|
||||
resp, err = clientconn.Do(req)
|
||||
if err != nil {
|
||||
@ -283,11 +296,10 @@ func (c *Client) do(method, path string, data interface{}) ([]byte, int, error)
|
||||
return body, resp.StatusCode, nil
|
||||
}
|
||||
|
||||
func (c *Client) stream(method, path string, headers map[string]string, in io.Reader, out io.Writer) error {
|
||||
func (c *Client) stream(method, path string, setRawTerminal bool, headers map[string]string, in io.Reader, stdout, stderr io.Writer) error {
|
||||
if (method == "POST" || method == "PUT") && in == nil {
|
||||
in = bytes.NewReader(nil)
|
||||
}
|
||||
|
||||
if path != "/version" && !c.SkipServerVersionCheck && c.expectedApiVersion == nil {
|
||||
err := c.checkApiVersion()
|
||||
if err != nil {
|
||||
@ -308,8 +320,11 @@ func (c *Client) stream(method, path string, headers map[string]string, in io.Re
|
||||
var resp *http.Response
|
||||
protocol := c.endpointURL.Scheme
|
||||
address := c.endpointURL.Path
|
||||
if out == nil {
|
||||
out = ioutil.Discard
|
||||
if stdout == nil {
|
||||
stdout = ioutil.Discard
|
||||
}
|
||||
if stderr == nil {
|
||||
stderr = ioutil.Discard
|
||||
}
|
||||
if protocol == "unix" {
|
||||
dial, err := net.Dial(protocol, address)
|
||||
@ -346,20 +361,23 @@ func (c *Client) stream(method, path string, headers map[string]string, in io.Re
|
||||
return err
|
||||
}
|
||||
if m.Stream != "" {
|
||||
fmt.Fprint(out, m.Stream)
|
||||
fmt.Fprint(stdout, m.Stream)
|
||||
} else if m.Progress != "" {
|
||||
fmt.Fprintf(out, "%s %s\r", m.Status, m.Progress)
|
||||
fmt.Fprintf(stdout, "%s %s\r", m.Status, m.Progress)
|
||||
} else if m.Error != "" {
|
||||
return errors.New(m.Error)
|
||||
}
|
||||
if m.Status != "" {
|
||||
fmt.Fprintln(out, m.Status)
|
||||
fmt.Fprintln(stdout, m.Status)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if _, err := io.Copy(out, resp.Body); err != nil {
|
||||
return err
|
||||
if setRawTerminal {
|
||||
_, err = io.Copy(stdout, resp.Body)
|
||||
} else {
|
||||
_, err = utils.StdCopy(stdout, stderr, resp.Body)
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -371,6 +389,12 @@ func (c *Client) hijack(method, path string, success chan struct{}, setRawTermin
|
||||
return err
|
||||
}
|
||||
}
|
||||
if stdout == nil {
|
||||
stdout = ioutil.Discard
|
||||
}
|
||||
if stderr == nil {
|
||||
stderr = ioutil.Discard
|
||||
}
|
||||
req, err := http.NewRequest(method, c.getURL(path), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -148,6 +148,25 @@ func TestQueryString(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewApiVersionFailures(t *testing.T) {
|
||||
var tests = []struct {
|
||||
input string
|
||||
expectedError string
|
||||
}{
|
||||
{"1-0", `Unable to parse version "1-0"`},
|
||||
{"1.0-beta", `Unable to parse version "1.0-beta": "0-beta" is not an integer`},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
v, err := NewApiVersion(tt.input)
|
||||
if v != nil {
|
||||
t.Errorf("Expected <nil> version, got %v.", v)
|
||||
}
|
||||
if err.Error() != tt.expectedError {
|
||||
t.Errorf("NewApiVersion(%q): wrong error. Want %q. Got %q", tt.input, tt.expectedError, err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestApiVersions(t *testing.T) {
|
||||
var tests = []struct {
|
||||
a string
|
||||
@ -192,6 +211,41 @@ func TestApiVersions(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPing(t *testing.T) {
|
||||
fakeRT := &FakeRoundTripper{message: "", status: http.StatusOK}
|
||||
client := newTestClient(fakeRT)
|
||||
err := client.Ping()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPingFailing(t *testing.T) {
|
||||
fakeRT := &FakeRoundTripper{message: "", status: http.StatusInternalServerError}
|
||||
client := newTestClient(fakeRT)
|
||||
err := client.Ping()
|
||||
if err == nil {
|
||||
t.Fatal("Expected non nil error, got nil")
|
||||
}
|
||||
expectedErrMsg := "API error (500): "
|
||||
if err.Error() != expectedErrMsg {
|
||||
t.Fatalf("Expected error to be %q, got: %q", expectedErrMsg, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestPingFailingWrongStatus(t *testing.T) {
|
||||
fakeRT := &FakeRoundTripper{message: "", status: http.StatusAccepted}
|
||||
client := newTestClient(fakeRT)
|
||||
err := client.Ping()
|
||||
if err == nil {
|
||||
t.Fatal("Expected non nil error, got nil")
|
||||
}
|
||||
expectedErrMsg := "API error (202): "
|
||||
if err.Error() != expectedErrMsg {
|
||||
t.Fatalf("Expected error to be %q, got: %q", expectedErrMsg, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
type FakeRoundTripper struct {
|
||||
message string
|
||||
status int
|
||||
|
@ -13,7 +13,6 @@ import (
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
@ -87,22 +86,19 @@ func (p Port) Proto() string {
|
||||
|
||||
// State represents the state of a container.
|
||||
type State struct {
|
||||
sync.RWMutex
|
||||
Running bool
|
||||
Paused bool
|
||||
Pid int
|
||||
ExitCode int
|
||||
StartedAt time.Time
|
||||
FinishedAt time.Time
|
||||
Ghost bool
|
||||
}
|
||||
|
||||
// String returns the string representation of a state.
|
||||
func (s *State) String() string {
|
||||
s.RLock()
|
||||
defer s.RUnlock()
|
||||
if s.Running {
|
||||
if s.Ghost {
|
||||
return "Ghost"
|
||||
if s.Paused {
|
||||
return "paused"
|
||||
}
|
||||
return fmt.Sprintf("Up %s", time.Now().UTC().Sub(s.StartedAt))
|
||||
}
|
||||
@ -162,8 +158,8 @@ type Config struct {
|
||||
Hostname string
|
||||
Domainname string
|
||||
User string
|
||||
Memory int64
|
||||
MemorySwap int64
|
||||
Memory uint64
|
||||
MemorySwap uint64
|
||||
CpuShares int64
|
||||
AttachStdin bool
|
||||
AttachStdout bool
|
||||
@ -351,6 +347,36 @@ func (c *Client) RestartContainer(id string, timeout uint) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// PauseContainer pauses the given container.
|
||||
//
|
||||
// See http://goo.gl/AM5t42 for more details.
|
||||
func (c *Client) PauseContainer(id string) error {
|
||||
path := fmt.Sprintf("/containers/%s/pause", id)
|
||||
_, status, err := c.do("POST", path, nil)
|
||||
if status == http.StatusNotFound {
|
||||
return &NoSuchContainer{ID: id}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnpauseContainer pauses the given container.
|
||||
//
|
||||
// See http://goo.gl/eBrNSL for more details.
|
||||
func (c *Client) UnpauseContainer(id string) error {
|
||||
path := fmt.Sprintf("/containers/%s/unpause", id)
|
||||
_, status, err := c.do("POST", path, nil)
|
||||
if status == http.StatusNotFound {
|
||||
return &NoSuchContainer{ID: id}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// KillContainerOptions represents the set of options that can be used in a
|
||||
// call to KillContainer.
|
||||
type KillContainerOptions struct {
|
||||
@ -542,10 +568,15 @@ func (c *Client) AttachToContainer(opts AttachToContainerOptions) error {
|
||||
type LogsOptions struct {
|
||||
Container string `qs:"-"`
|
||||
OutputStream io.Writer `qs:"-"`
|
||||
ErrorStream io.Writer `qs:"-"`
|
||||
Follow bool
|
||||
Stdout bool
|
||||
Stderr bool
|
||||
Timestamps bool
|
||||
Tail string
|
||||
|
||||
// Use raw terminal? Usually true when the container contains a TTY.
|
||||
RawTerminal bool `qs:"-"`
|
||||
}
|
||||
|
||||
// Logs gets stdout and stderr logs from the specified container.
|
||||
@ -555,8 +586,11 @@ func (c *Client) Logs(opts LogsOptions) error {
|
||||
if opts.Container == "" {
|
||||
return &NoSuchContainer{ID: opts.Container}
|
||||
}
|
||||
if opts.Tail == "" {
|
||||
opts.Tail = "all"
|
||||
}
|
||||
path := "/containers/" + opts.Container + "/logs?" + queryString(opts)
|
||||
return c.stream("GET", path, nil, nil, opts.OutputStream)
|
||||
return c.stream("GET", path, opts.RawTerminal, nil, nil, opts.OutputStream, opts.ErrorStream)
|
||||
}
|
||||
|
||||
// ResizeContainerTTY resizes the terminal to the given height and width.
|
||||
@ -586,7 +620,7 @@ func (c *Client) ExportContainer(opts ExportContainerOptions) error {
|
||||
return NoSuchContainer{ID: opts.ID}
|
||||
}
|
||||
url := fmt.Sprintf("/containers/%s/export", opts.ID)
|
||||
return c.stream("GET", url, nil, nil, opts.OutputStream)
|
||||
return c.stream("GET", url, true, nil, nil, opts.OutputStream, nil)
|
||||
}
|
||||
|
||||
// NoSuchContainer is the error returned when a given container does not exist.
|
||||
|
@ -14,12 +14,32 @@ import (
|
||||
"net/url"
|
||||
"os"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestStateString(t *testing.T) {
|
||||
started := time.Now().Add(-3 * time.Hour)
|
||||
var tests = []struct {
|
||||
input State
|
||||
expected string
|
||||
}{
|
||||
{State{Running: true, Paused: true}, "^paused$"},
|
||||
{State{Running: true, StartedAt: started}, "^Up 3h.*$"},
|
||||
{State{Running: false, ExitCode: 7}, "^Exit 7$"},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
re := regexp.MustCompile(tt.expected)
|
||||
if got := tt.input.String(); !re.MatchString(got) {
|
||||
t.Errorf("State.String(): wrong result. Want %q. Got %q.", tt.expected, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestListContainers(t *testing.T) {
|
||||
jsonContainers := `[
|
||||
{
|
||||
@ -132,8 +152,8 @@ func TestInspectContainer(t *testing.T) {
|
||||
"Config": {
|
||||
"Hostname": "4fa6e0f0c678",
|
||||
"User": "",
|
||||
"Memory": 0,
|
||||
"MemorySwap": 0,
|
||||
"Memory": 17179869184,
|
||||
"MemorySwap": 34359738368,
|
||||
"AttachStdin": false,
|
||||
"AttachStdout": true,
|
||||
"AttachStderr": true,
|
||||
@ -445,6 +465,60 @@ func TestRestartContainerNotFound(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPauseContainer(t *testing.T) {
|
||||
fakeRT := &FakeRoundTripper{message: "", status: http.StatusNoContent}
|
||||
client := newTestClient(fakeRT)
|
||||
id := "4fa6e0f0c6786287e131c3852c58a2e01cc697a68231826813597e4994f1d6e2"
|
||||
err := client.PauseContainer(id)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
req := fakeRT.requests[0]
|
||||
if req.Method != "POST" {
|
||||
t.Errorf("PauseContainer(%q): wrong HTTP method. Want %q. Got %q.", id, "POST", req.Method)
|
||||
}
|
||||
expectedURL, _ := url.Parse(client.getURL("/containers/" + id + "/pause"))
|
||||
if gotPath := req.URL.Path; gotPath != expectedURL.Path {
|
||||
t.Errorf("PauseContainer(%q): Wrong path in request. Want %q. Got %q.", id, expectedURL.Path, gotPath)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPauseContainerNotFound(t *testing.T) {
|
||||
client := newTestClient(&FakeRoundTripper{message: "no such container", status: http.StatusNotFound})
|
||||
err := client.PauseContainer("a2334")
|
||||
expected := &NoSuchContainer{ID: "a2334"}
|
||||
if !reflect.DeepEqual(err, expected) {
|
||||
t.Errorf("PauseContainer: Wrong error returned. Want %#v. Got %#v.", expected, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnpauseContainer(t *testing.T) {
|
||||
fakeRT := &FakeRoundTripper{message: "", status: http.StatusNoContent}
|
||||
client := newTestClient(fakeRT)
|
||||
id := "4fa6e0f0c6786287e131c3852c58a2e01cc697a68231826813597e4994f1d6e2"
|
||||
err := client.UnpauseContainer(id)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
req := fakeRT.requests[0]
|
||||
if req.Method != "POST" {
|
||||
t.Errorf("PauseContainer(%q): wrong HTTP method. Want %q. Got %q.", id, "POST", req.Method)
|
||||
}
|
||||
expectedURL, _ := url.Parse(client.getURL("/containers/" + id + "/unpause"))
|
||||
if gotPath := req.URL.Path; gotPath != expectedURL.Path {
|
||||
t.Errorf("PauseContainer(%q): Wrong path in request. Want %q. Got %q.", id, expectedURL.Path, gotPath)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnpauseContainerNotFound(t *testing.T) {
|
||||
client := newTestClient(&FakeRoundTripper{message: "no such container", status: http.StatusNotFound})
|
||||
err := client.UnpauseContainer("a2334")
|
||||
expected := &NoSuchContainer{ID: "a2334"}
|
||||
if !reflect.DeepEqual(err, expected) {
|
||||
t.Errorf("PauseContainer: Wrong error returned. Want %#v. Got %#v.", expected, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestKillContainer(t *testing.T) {
|
||||
fakeRT := &FakeRoundTripper{message: "", status: http.StatusNoContent}
|
||||
client := newTestClient(fakeRT)
|
||||
@ -736,7 +810,7 @@ func TestAttachToContainer(t *testing.T) {
|
||||
Stream: true,
|
||||
RawTerminal: true,
|
||||
}
|
||||
var err = client.AttachToContainer(opts)
|
||||
err := client.AttachToContainer(opts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -781,6 +855,63 @@ func TestAttachToContainerSentinel(t *testing.T) {
|
||||
success <- <-success
|
||||
}
|
||||
|
||||
func TestAttachToContainerNilStdout(t *testing.T) {
|
||||
var reader = strings.NewReader("send value")
|
||||
var req http.Request
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte{1, 0, 0, 0, 0, 0, 0, 5})
|
||||
w.Write([]byte("hello"))
|
||||
req = *r
|
||||
}))
|
||||
defer server.Close()
|
||||
client, _ := NewClient(server.URL)
|
||||
client.SkipServerVersionCheck = true
|
||||
var stderr bytes.Buffer
|
||||
opts := AttachToContainerOptions{
|
||||
Container: "a123456",
|
||||
OutputStream: nil,
|
||||
ErrorStream: &stderr,
|
||||
InputStream: reader,
|
||||
Stdin: true,
|
||||
Stdout: true,
|
||||
Stderr: true,
|
||||
Stream: true,
|
||||
RawTerminal: true,
|
||||
}
|
||||
err := client.AttachToContainer(opts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAttachToContainerNilStderr(t *testing.T) {
|
||||
var reader = strings.NewReader("send value")
|
||||
var req http.Request
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte{1, 0, 0, 0, 0, 0, 0, 5})
|
||||
w.Write([]byte("hello"))
|
||||
req = *r
|
||||
}))
|
||||
defer server.Close()
|
||||
client, _ := NewClient(server.URL)
|
||||
client.SkipServerVersionCheck = true
|
||||
var stdout bytes.Buffer
|
||||
opts := AttachToContainerOptions{
|
||||
Container: "a123456",
|
||||
OutputStream: &stdout,
|
||||
InputStream: reader,
|
||||
Stdin: true,
|
||||
Stdout: true,
|
||||
Stderr: true,
|
||||
Stream: true,
|
||||
RawTerminal: true,
|
||||
}
|
||||
err := client.AttachToContainer(opts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAttachToContainerRawTerminalFalse(t *testing.T) {
|
||||
input := strings.NewReader("send value")
|
||||
var req http.Request
|
||||
@ -838,6 +969,8 @@ func TestAttachToContainerWithoutContainer(t *testing.T) {
|
||||
func TestLogs(t *testing.T) {
|
||||
var req http.Request
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
prefix := []byte{1, 0, 0, 0, 0, 0, 0, 19}
|
||||
w.Write(prefix)
|
||||
w.Write([]byte("something happened!"))
|
||||
req = *r
|
||||
}))
|
||||
@ -873,6 +1006,7 @@ func TestLogs(t *testing.T) {
|
||||
"stdout": {"1"},
|
||||
"stderr": {"1"},
|
||||
"timestamps": {"1"},
|
||||
"tail": {"all"},
|
||||
}
|
||||
got := map[string][]string(req.URL.Query())
|
||||
if !reflect.DeepEqual(got, expectedQs) {
|
||||
@ -880,6 +1014,133 @@ func TestLogs(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogsNilStdoutDoesntFail(t *testing.T) {
|
||||
var req http.Request
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
prefix := []byte{1, 0, 0, 0, 0, 0, 0, 19}
|
||||
w.Write(prefix)
|
||||
w.Write([]byte("something happened!"))
|
||||
req = *r
|
||||
}))
|
||||
defer server.Close()
|
||||
client, _ := NewClient(server.URL)
|
||||
client.SkipServerVersionCheck = true
|
||||
opts := LogsOptions{
|
||||
Container: "a123456",
|
||||
Follow: true,
|
||||
Stdout: true,
|
||||
Stderr: true,
|
||||
Timestamps: true,
|
||||
}
|
||||
err := client.Logs(opts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogsNilStderrDoesntFail(t *testing.T) {
|
||||
var req http.Request
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
prefix := []byte{2, 0, 0, 0, 0, 0, 0, 19}
|
||||
w.Write(prefix)
|
||||
w.Write([]byte("something happened!"))
|
||||
req = *r
|
||||
}))
|
||||
defer server.Close()
|
||||
client, _ := NewClient(server.URL)
|
||||
client.SkipServerVersionCheck = true
|
||||
opts := LogsOptions{
|
||||
Container: "a123456",
|
||||
Follow: true,
|
||||
Stdout: true,
|
||||
Stderr: true,
|
||||
Timestamps: true,
|
||||
}
|
||||
err := client.Logs(opts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogsSpecifyingTail(t *testing.T) {
|
||||
var req http.Request
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
prefix := []byte{1, 0, 0, 0, 0, 0, 0, 19}
|
||||
w.Write(prefix)
|
||||
w.Write([]byte("something happened!"))
|
||||
req = *r
|
||||
}))
|
||||
defer server.Close()
|
||||
client, _ := NewClient(server.URL)
|
||||
client.SkipServerVersionCheck = true
|
||||
var buf bytes.Buffer
|
||||
opts := LogsOptions{
|
||||
Container: "a123456",
|
||||
OutputStream: &buf,
|
||||
Follow: true,
|
||||
Stdout: true,
|
||||
Stderr: true,
|
||||
Timestamps: true,
|
||||
Tail: "100",
|
||||
}
|
||||
err := client.Logs(opts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
expected := "something happened!"
|
||||
if buf.String() != expected {
|
||||
t.Errorf("Logs: wrong output. Want %q. Got %q.", expected, buf.String())
|
||||
}
|
||||
if req.Method != "GET" {
|
||||
t.Errorf("Logs: wrong HTTP method. Want GET. Got %s.", req.Method)
|
||||
}
|
||||
u, _ := url.Parse(client.getURL("/containers/a123456/logs"))
|
||||
if req.URL.Path != u.Path {
|
||||
t.Errorf("AttachToContainer for logs: wrong HTTP path. Want %q. Got %q.", u.Path, req.URL.Path)
|
||||
}
|
||||
expectedQs := map[string][]string{
|
||||
"follow": {"1"},
|
||||
"stdout": {"1"},
|
||||
"stderr": {"1"},
|
||||
"timestamps": {"1"},
|
||||
"tail": {"100"},
|
||||
}
|
||||
got := map[string][]string(req.URL.Query())
|
||||
if !reflect.DeepEqual(got, expectedQs) {
|
||||
t.Errorf("Logs: wrong query string. Want %#v. Got %#v.", expectedQs, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogsRawTerminal(t *testing.T) {
|
||||
var req http.Request
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte("something happened!"))
|
||||
req = *r
|
||||
}))
|
||||
defer server.Close()
|
||||
client, _ := NewClient(server.URL)
|
||||
client.SkipServerVersionCheck = true
|
||||
var buf bytes.Buffer
|
||||
opts := LogsOptions{
|
||||
Container: "a123456",
|
||||
OutputStream: &buf,
|
||||
Follow: true,
|
||||
RawTerminal: true,
|
||||
Stdout: true,
|
||||
Stderr: true,
|
||||
Timestamps: true,
|
||||
Tail: "100",
|
||||
}
|
||||
err := client.Logs(opts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
expected := "something happened!"
|
||||
if buf.String() != expected {
|
||||
t.Errorf("Logs: wrong output. Want %q. Got %q.", expected, buf.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogsNoContainer(t *testing.T) {
|
||||
var client Client
|
||||
err := client.Logs(LogsOptions{})
|
||||
|
@ -154,6 +154,9 @@ type PushImageOptions struct {
|
||||
// Name of the image
|
||||
Name string
|
||||
|
||||
// Tag of the image
|
||||
Tag string
|
||||
|
||||
// Registry server to push the image
|
||||
Registry string
|
||||
|
||||
@ -187,7 +190,7 @@ func (c *Client) PushImage(opts PushImageOptions, auth AuthConfiguration) error
|
||||
|
||||
headers["X-Registry-Auth"] = base64.URLEncoding.EncodeToString(buf.Bytes())
|
||||
|
||||
return c.stream("POST", path, headers, nil, opts.OutputStream)
|
||||
return c.stream("POST", path, true, headers, nil, opts.OutputStream, nil)
|
||||
}
|
||||
|
||||
// PullImageOptions present the set of options available for pulling an image
|
||||
@ -219,7 +222,7 @@ func (c *Client) PullImage(opts PullImageOptions, auth AuthConfiguration) error
|
||||
|
||||
func (c *Client) createImage(qs string, headers map[string]string, in io.Reader, w io.Writer) error {
|
||||
path := "/images/create?" + qs
|
||||
return c.stream("POST", path, headers, in, w)
|
||||
return c.stream("POST", path, true, headers, in, w, nil)
|
||||
}
|
||||
|
||||
// ImportImageOptions present the set of informations available for importing
|
||||
@ -286,13 +289,14 @@ func (c *Client) BuildImage(opts BuildImageOptions) error {
|
||||
return ErrMissingRepo
|
||||
}
|
||||
return c.stream("POST", fmt.Sprintf("/build?%s",
|
||||
queryString(&opts)), headers, opts.InputStream, opts.OutputStream)
|
||||
queryString(&opts)), true, headers, opts.InputStream, opts.OutputStream, nil)
|
||||
}
|
||||
|
||||
// TagImageOptions present the set of options to tag an image
|
||||
type TagImageOptions struct {
|
||||
Repo string `qs:"repo"`
|
||||
Force bool `qs:"force"`
|
||||
Repo string
|
||||
Tag string
|
||||
Force bool
|
||||
}
|
||||
|
||||
// TagImage adds a tag to the image 'name'
|
||||
|
@ -18,7 +18,6 @@ import (
|
||||
mathrand "math/rand"
|
||||
"net"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -34,43 +33,55 @@ import (
|
||||
//
|
||||
// For more details on the remote API, check http://goo.gl/yMI1S.
|
||||
type DockerServer struct {
|
||||
containers []*docker.Container
|
||||
cMut sync.RWMutex
|
||||
images []docker.Image
|
||||
iMut sync.RWMutex
|
||||
imgIDs map[string]string
|
||||
listener net.Listener
|
||||
mux *mux.Router
|
||||
hook func(*http.Request)
|
||||
failures map[string]FailureSpec
|
||||
}
|
||||
|
||||
// FailureSpec is used with PrepareFailure and describes in which situations
|
||||
// the request should fail. UrlRegex is mandatory, if a container id is sent
|
||||
// on the request you can also specify the other properties.
|
||||
type FailureSpec struct {
|
||||
UrlRegex string
|
||||
ContainerPath string
|
||||
ContainerArgs []string
|
||||
containers []*docker.Container
|
||||
cMut sync.RWMutex
|
||||
images []docker.Image
|
||||
iMut sync.RWMutex
|
||||
imgIDs map[string]string
|
||||
listener net.Listener
|
||||
mux *mux.Router
|
||||
hook func(*http.Request)
|
||||
failures map[string]string
|
||||
customHandlers map[string]http.Handler
|
||||
handlerMutex sync.RWMutex
|
||||
cChan chan<- *docker.Container
|
||||
}
|
||||
|
||||
// NewServer returns a new instance of the fake server, in standalone mode. Use
|
||||
// the method URL to get the URL of the server.
|
||||
//
|
||||
// It receives the bind address (use 127.0.0.1:0 for getting an available port
|
||||
// on the host) and a hook function, that will be called on every request.
|
||||
func NewServer(bind string, hook func(*http.Request)) (*DockerServer, error) {
|
||||
// on the host), a channel of containers and a hook function, that will be
|
||||
// called on every request.
|
||||
//
|
||||
// The fake server will send containers in the channel whenever the container
|
||||
// changes its state, via the HTTP API (i.e.: create, start and stop). This
|
||||
// channel may be nil, which means that the server won't notify on state
|
||||
// changes.
|
||||
func NewServer(bind string, containerChan chan<- *docker.Container, hook func(*http.Request)) (*DockerServer, error) {
|
||||
listener, err := net.Listen("tcp", bind)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
server := DockerServer{listener: listener, imgIDs: make(map[string]string), hook: hook,
|
||||
failures: make(map[string]FailureSpec)}
|
||||
server := DockerServer{
|
||||
listener: listener,
|
||||
imgIDs: make(map[string]string),
|
||||
hook: hook,
|
||||
failures: make(map[string]string),
|
||||
customHandlers: make(map[string]http.Handler),
|
||||
cChan: containerChan,
|
||||
}
|
||||
server.buildMuxer()
|
||||
go http.Serve(listener, &server)
|
||||
return &server, nil
|
||||
}
|
||||
|
||||
func (s *DockerServer) notify(container *docker.Container) {
|
||||
if s.cChan != nil {
|
||||
s.cChan <- container
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerServer) buildMuxer() {
|
||||
s.mux = mux.NewRouter()
|
||||
s.mux.Path("/commit").Methods("POST").HandlerFunc(s.handlerWrapper(s.commitContainer))
|
||||
@ -79,6 +90,8 @@ func (s *DockerServer) buildMuxer() {
|
||||
s.mux.Path("/containers/{id:.*}/json").Methods("GET").HandlerFunc(s.handlerWrapper(s.inspectContainer))
|
||||
s.mux.Path("/containers/{id:.*}/start").Methods("POST").HandlerFunc(s.handlerWrapper(s.startContainer))
|
||||
s.mux.Path("/containers/{id:.*}/stop").Methods("POST").HandlerFunc(s.handlerWrapper(s.stopContainer))
|
||||
s.mux.Path("/containers/{id:.*}/pause").Methods("POST").HandlerFunc(s.handlerWrapper(s.pauseContainer))
|
||||
s.mux.Path("/containers/{id:.*}/unpause").Methods("POST").HandlerFunc(s.handlerWrapper(s.unpauseContainer))
|
||||
s.mux.Path("/containers/{id:.*}/wait").Methods("POST").HandlerFunc(s.handlerWrapper(s.waitContainer))
|
||||
s.mux.Path("/containers/{id:.*}/attach").Methods("POST").HandlerFunc(s.handlerWrapper(s.attachContainer))
|
||||
s.mux.Path("/containers/{id:.*}").Methods("DELETE").HandlerFunc(s.handlerWrapper(s.removeContainer))
|
||||
@ -89,19 +102,45 @@ func (s *DockerServer) buildMuxer() {
|
||||
s.mux.Path("/images/{name:.*}/json").Methods("GET").HandlerFunc(s.handlerWrapper(s.inspectImage))
|
||||
s.mux.Path("/images/{name:.*}/push").Methods("POST").HandlerFunc(s.handlerWrapper(s.pushImage))
|
||||
s.mux.Path("/events").Methods("GET").HandlerFunc(s.listEvents)
|
||||
s.mux.Path("/_ping").Methods("GET").HandlerFunc(s.handlerWrapper(s.pingDocker))
|
||||
}
|
||||
|
||||
// PrepareFailure adds a new expected failure based on a FailureSpec
|
||||
// it receives an id for the failure and the spec.
|
||||
func (s *DockerServer) PrepareFailure(id string, spec FailureSpec) {
|
||||
s.failures[id] = spec
|
||||
// PrepareFailure adds a new expected failure based on a URL regexp it receives
|
||||
// an id for the failure.
|
||||
func (s *DockerServer) PrepareFailure(id string, urlRegexp string) {
|
||||
s.failures[id] = urlRegexp
|
||||
}
|
||||
|
||||
// ResetFailure removes an expected failure identified by the id
|
||||
// ResetFailure removes an expected failure identified by the given id.
|
||||
func (s *DockerServer) ResetFailure(id string) {
|
||||
delete(s.failures, id)
|
||||
}
|
||||
|
||||
// CustomHandler registers a custom handler for a specific path.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// server.CustomHandler("/containers/json", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// http.Error(w, "Something wrong is not right", http.StatusInternalServerError)
|
||||
// }))
|
||||
func (s *DockerServer) CustomHandler(path string, handler http.Handler) {
|
||||
s.handlerMutex.Lock()
|
||||
s.customHandlers[path] = handler
|
||||
s.handlerMutex.Unlock()
|
||||
}
|
||||
|
||||
// MutateContainer changes the state of a container, returning an error if the
|
||||
// given id does not match to any container "running" in the server.
|
||||
func (s *DockerServer) MutateContainer(id string, state docker.State) error {
|
||||
for _, container := range s.containers {
|
||||
if container.ID == id {
|
||||
container.State = state
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return errors.New("container not found")
|
||||
}
|
||||
|
||||
// Stop stops the server.
|
||||
func (s *DockerServer) Stop() {
|
||||
if s.listener != nil {
|
||||
@ -119,6 +158,12 @@ func (s *DockerServer) URL() string {
|
||||
|
||||
// ServeHTTP handles HTTP requests sent to the server.
|
||||
func (s *DockerServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
s.handlerMutex.RLock()
|
||||
defer s.handlerMutex.RUnlock()
|
||||
if handler, ok := s.customHandlers[r.URL.Path]; ok {
|
||||
handler.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
s.mux.ServeHTTP(w, r)
|
||||
if s.hook != nil {
|
||||
s.hook(r)
|
||||
@ -127,8 +172,8 @@ func (s *DockerServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
func (s *DockerServer) handlerWrapper(f func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
for errorId, spec := range s.failures {
|
||||
matched, err := regexp.MatchString(spec.UrlRegex, r.URL.Path)
|
||||
for errorID, urlRegexp := range s.failures {
|
||||
matched, err := regexp.MatchString(urlRegexp, r.URL.Path)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
@ -136,21 +181,7 @@ func (s *DockerServer) handlerWrapper(f func(http.ResponseWriter, *http.Request)
|
||||
if !matched {
|
||||
continue
|
||||
}
|
||||
id := mux.Vars(r)["id"]
|
||||
if id != "" {
|
||||
container, _, err := s.findContainer(id)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if spec.ContainerPath != "" && container.Path != spec.ContainerPath {
|
||||
continue
|
||||
}
|
||||
if spec.ContainerArgs != nil && reflect.DeepEqual(container.Args, spec.ContainerArgs) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
http.Error(w, errorId, http.StatusBadRequest)
|
||||
http.Error(w, errorID, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
f(w, r)
|
||||
@ -272,6 +303,7 @@ func (s *DockerServer) createContainer(w http.ResponseWriter, r *http.Request) {
|
||||
s.cMut.Lock()
|
||||
s.containers = append(s.containers, &container)
|
||||
s.cMut.Unlock()
|
||||
s.notify(&container)
|
||||
var c = struct{ ID string }{ID: container.ID}
|
||||
json.NewEncoder(w).Encode(c)
|
||||
}
|
||||
@ -308,6 +340,7 @@ func (s *DockerServer) startContainer(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
container.State.Running = true
|
||||
s.notify(container)
|
||||
}
|
||||
|
||||
func (s *DockerServer) stopContainer(w http.ResponseWriter, r *http.Request) {
|
||||
@ -325,6 +358,41 @@ func (s *DockerServer) stopContainer(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
container.State.Running = false
|
||||
s.notify(container)
|
||||
}
|
||||
|
||||
func (s *DockerServer) pauseContainer(w http.ResponseWriter, r *http.Request) {
|
||||
id := mux.Vars(r)["id"]
|
||||
container, _, err := s.findContainer(id)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
s.cMut.Lock()
|
||||
defer s.cMut.Unlock()
|
||||
if container.State.Paused {
|
||||
http.Error(w, "Container already paused", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
container.State.Paused = true
|
||||
}
|
||||
|
||||
func (s *DockerServer) unpauseContainer(w http.ResponseWriter, r *http.Request) {
|
||||
id := mux.Vars(r)["id"]
|
||||
container, _, err := s.findContainer(id)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
s.cMut.Lock()
|
||||
defer s.cMut.Unlock()
|
||||
if !container.State.Paused {
|
||||
http.Error(w, "Container not paused", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
container.State.Paused = false
|
||||
}
|
||||
|
||||
func (s *DockerServer) attachContainer(w http.ResponseWriter, r *http.Request) {
|
||||
@ -361,7 +429,8 @@ func (s *DockerServer) waitContainer(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
s.cMut.RUnlock()
|
||||
}
|
||||
w.Write([]byte(`{"StatusCode":0}`))
|
||||
result := map[string]int{"StatusCode": container.State.ExitCode}
|
||||
json.NewEncoder(w).Encode(result)
|
||||
}
|
||||
|
||||
func (s *DockerServer) removeContainer(w http.ResponseWriter, r *http.Request) {
|
||||
@ -547,6 +616,10 @@ func (s *DockerServer) listEvents(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerServer) pingDocker(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
func (s *DockerServer) generateEvent() *docker.APIEvents {
|
||||
var eventType string
|
||||
switch mathrand.Intn(4) {
|
||||
|
@ -20,7 +20,7 @@ import (
|
||||
)
|
||||
|
||||
func TestNewServer(t *testing.T) {
|
||||
server, err := NewServer("127.0.0.1:0", nil)
|
||||
server, err := NewServer("127.0.0.1:0", nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -33,7 +33,7 @@ func TestNewServer(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestServerStop(t *testing.T) {
|
||||
server, err := NewServer("127.0.0.1:0", nil)
|
||||
server, err := NewServer("127.0.0.1:0", nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -50,7 +50,7 @@ func TestServerStopNoListener(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestServerURL(t *testing.T) {
|
||||
server, err := NewServer("127.0.0.1:0", nil)
|
||||
server, err := NewServer("127.0.0.1:0", nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -71,7 +71,7 @@ func TestServerURLNoListener(t *testing.T) {
|
||||
|
||||
func TestHandleWithHook(t *testing.T) {
|
||||
var called bool
|
||||
server, _ := NewServer("127.0.0.1:0", func(*http.Request) { called = true })
|
||||
server, _ := NewServer("127.0.0.1:0", nil, func(*http.Request) { called = true })
|
||||
defer server.Stop()
|
||||
recorder := httptest.NewRecorder()
|
||||
request, _ := http.NewRequest("GET", "/containers/json?all=1", nil)
|
||||
@ -81,6 +81,25 @@ func TestHandleWithHook(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCustomHandler(t *testing.T) {
|
||||
var called bool
|
||||
server, _ := NewServer("127.0.0.1:0", nil, nil)
|
||||
addContainers(server, 2)
|
||||
server.CustomHandler("/containers/json", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
fmt.Fprint(w, "Hello world")
|
||||
}))
|
||||
recorder := httptest.NewRecorder()
|
||||
request, _ := http.NewRequest("GET", "/containers/json?all=1", nil)
|
||||
server.ServeHTTP(recorder, request)
|
||||
if !called {
|
||||
t.Error("Did not call the custom handler")
|
||||
}
|
||||
if got := recorder.Body.String(); got != "Hello world" {
|
||||
t.Errorf("Wrong output for custom handler: want %q. Got %q.", "Hello world", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestListContainers(t *testing.T) {
|
||||
server := DockerServer{}
|
||||
addContainers(&server, 2)
|
||||
@ -158,6 +177,25 @@ func TestCreateContainer(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateContainerWithNotifyChannel(t *testing.T) {
|
||||
ch := make(chan *docker.Container, 1)
|
||||
server := DockerServer{}
|
||||
server.imgIDs = map[string]string{"base": "a1234"}
|
||||
server.cChan = ch
|
||||
server.buildMuxer()
|
||||
recorder := httptest.NewRecorder()
|
||||
body := `{"Hostname":"", "User":"", "Memory":0, "MemorySwap":0, "AttachStdin":false, "AttachStdout":true, "AttachStderr":true,
|
||||
"PortSpecs":null, "Tty":false, "OpenStdin":false, "StdinOnce":false, "Env":null, "Cmd":["date"], "Image":"base", "Volumes":{}, "VolumesFrom":""}`
|
||||
request, _ := http.NewRequest("POST", "/containers/create", strings.NewReader(body))
|
||||
server.ServeHTTP(recorder, request)
|
||||
if recorder.Code != http.StatusCreated {
|
||||
t.Errorf("CreateContainer: wrong status. Want %d. Got %d.", http.StatusCreated, recorder.Code)
|
||||
}
|
||||
if notified := <-ch; notified != server.containers[0] {
|
||||
t.Errorf("CreateContainer: did not notify the proper container. Want %q. Got %q.", server.containers[0].ID, notified.ID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateContainerInvalidBody(t *testing.T) {
|
||||
server := DockerServer{}
|
||||
server.buildMuxer()
|
||||
@ -320,6 +358,25 @@ func TestStartContainer(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestStartContainerWithNotifyChannel(t *testing.T) {
|
||||
ch := make(chan *docker.Container, 1)
|
||||
server := DockerServer{}
|
||||
server.cChan = ch
|
||||
addContainers(&server, 1)
|
||||
addContainers(&server, 1)
|
||||
server.buildMuxer()
|
||||
recorder := httptest.NewRecorder()
|
||||
path := fmt.Sprintf("/containers/%s/start", server.containers[1].ID)
|
||||
request, _ := http.NewRequest("POST", path, nil)
|
||||
server.ServeHTTP(recorder, request)
|
||||
if recorder.Code != http.StatusOK {
|
||||
t.Errorf("StartContainer: wrong status code. Want %d. Got %d.", http.StatusOK, recorder.Code)
|
||||
}
|
||||
if notified := <-ch; notified != server.containers[1] {
|
||||
t.Errorf("StartContainer: did not notify the proper container. Want %q. Got %q.", server.containers[1].ID, notified.ID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStartContainerNotFound(t *testing.T) {
|
||||
server := DockerServer{}
|
||||
server.buildMuxer()
|
||||
@ -363,6 +420,26 @@ func TestStopContainer(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestStopContainerWithNotifyChannel(t *testing.T) {
|
||||
ch := make(chan *docker.Container, 1)
|
||||
server := DockerServer{}
|
||||
server.cChan = ch
|
||||
addContainers(&server, 1)
|
||||
addContainers(&server, 1)
|
||||
server.containers[1].State.Running = true
|
||||
server.buildMuxer()
|
||||
recorder := httptest.NewRecorder()
|
||||
path := fmt.Sprintf("/containers/%s/stop", server.containers[1].ID)
|
||||
request, _ := http.NewRequest("POST", path, nil)
|
||||
server.ServeHTTP(recorder, request)
|
||||
if recorder.Code != http.StatusNoContent {
|
||||
t.Errorf("StopContainer: wrong status code. Want %d. Got %d.", http.StatusNoContent, recorder.Code)
|
||||
}
|
||||
if notified := <-ch; notified != server.containers[1] {
|
||||
t.Errorf("StopContainer: did not notify the proper container. Want %q. Got %q.", server.containers[1].ID, notified.ID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStopContainerNotFound(t *testing.T) {
|
||||
server := DockerServer{}
|
||||
server.buildMuxer()
|
||||
@ -388,6 +465,90 @@ func TestStopContainerNotRunning(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPauseContainer(t *testing.T) {
|
||||
server := DockerServer{}
|
||||
addContainers(&server, 1)
|
||||
server.buildMuxer()
|
||||
recorder := httptest.NewRecorder()
|
||||
path := fmt.Sprintf("/containers/%s/pause", server.containers[0].ID)
|
||||
request, _ := http.NewRequest("POST", path, nil)
|
||||
server.ServeHTTP(recorder, request)
|
||||
if recorder.Code != http.StatusNoContent {
|
||||
t.Errorf("PauseContainer: wrong status code. Want %d. Got %d.", http.StatusNoContent, recorder.Code)
|
||||
}
|
||||
if !server.containers[0].State.Paused {
|
||||
t.Error("PauseContainer: did not pause the container")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPauseContainerAlreadyPaused(t *testing.T) {
|
||||
server := DockerServer{}
|
||||
addContainers(&server, 1)
|
||||
server.containers[0].State.Paused = true
|
||||
server.buildMuxer()
|
||||
recorder := httptest.NewRecorder()
|
||||
path := fmt.Sprintf("/containers/%s/pause", server.containers[0].ID)
|
||||
request, _ := http.NewRequest("POST", path, nil)
|
||||
server.ServeHTTP(recorder, request)
|
||||
if recorder.Code != http.StatusBadRequest {
|
||||
t.Errorf("PauseContainer: wrong status code. Want %d. Got %d.", http.StatusBadRequest, recorder.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPauseContainerNotFound(t *testing.T) {
|
||||
server := DockerServer{}
|
||||
server.buildMuxer()
|
||||
recorder := httptest.NewRecorder()
|
||||
path := "/containers/abc123/pause"
|
||||
request, _ := http.NewRequest("POST", path, nil)
|
||||
server.ServeHTTP(recorder, request)
|
||||
if recorder.Code != http.StatusNotFound {
|
||||
t.Errorf("PauseContainer: wrong status code. Want %d. Got %d.", http.StatusNotFound, recorder.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnpauseContainer(t *testing.T) {
|
||||
server := DockerServer{}
|
||||
addContainers(&server, 1)
|
||||
server.containers[0].State.Paused = true
|
||||
server.buildMuxer()
|
||||
recorder := httptest.NewRecorder()
|
||||
path := fmt.Sprintf("/containers/%s/unpause", server.containers[0].ID)
|
||||
request, _ := http.NewRequest("POST", path, nil)
|
||||
server.ServeHTTP(recorder, request)
|
||||
if recorder.Code != http.StatusNoContent {
|
||||
t.Errorf("UnpauseContainer: wrong status code. Want %d. Got %d.", http.StatusNoContent, recorder.Code)
|
||||
}
|
||||
if server.containers[0].State.Paused {
|
||||
t.Error("UnpauseContainer: did not unpause the container")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnpauseContainerNotPaused(t *testing.T) {
|
||||
server := DockerServer{}
|
||||
addContainers(&server, 1)
|
||||
server.buildMuxer()
|
||||
recorder := httptest.NewRecorder()
|
||||
path := fmt.Sprintf("/containers/%s/unpause", server.containers[0].ID)
|
||||
request, _ := http.NewRequest("POST", path, nil)
|
||||
server.ServeHTTP(recorder, request)
|
||||
if recorder.Code != http.StatusBadRequest {
|
||||
t.Errorf("UnpauseContainer: wrong status code. Want %d. Got %d.", http.StatusBadRequest, recorder.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnpauseContainerNotFound(t *testing.T) {
|
||||
server := DockerServer{}
|
||||
server.buildMuxer()
|
||||
recorder := httptest.NewRecorder()
|
||||
path := "/containers/abc123/unpause"
|
||||
request, _ := http.NewRequest("POST", path, nil)
|
||||
server.ServeHTTP(recorder, request)
|
||||
if recorder.Code != http.StatusNotFound {
|
||||
t.Errorf("UnpauseContainer: wrong status code. Want %d. Got %d.", http.StatusNotFound, recorder.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWaitContainer(t *testing.T) {
|
||||
server := DockerServer{}
|
||||
addContainers(&server, 1)
|
||||
@ -405,7 +566,25 @@ func TestWaitContainer(t *testing.T) {
|
||||
if recorder.Code != http.StatusOK {
|
||||
t.Errorf("WaitContainer: wrong status. Want %d. Got %d.", http.StatusOK, recorder.Code)
|
||||
}
|
||||
expected := `{"StatusCode":0}`
|
||||
expected := `{"StatusCode":0}` + "\n"
|
||||
if body := recorder.Body.String(); body != expected {
|
||||
t.Errorf("WaitContainer: wrong body. Want %q. Got %q.", expected, body)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWaitContainerStatus(t *testing.T) {
|
||||
server := DockerServer{}
|
||||
addContainers(&server, 1)
|
||||
server.buildMuxer()
|
||||
server.containers[0].State.ExitCode = 63
|
||||
recorder := httptest.NewRecorder()
|
||||
path := fmt.Sprintf("/containers/%s/wait", server.containers[0].ID)
|
||||
request, _ := http.NewRequest("POST", path, nil)
|
||||
server.ServeHTTP(recorder, request)
|
||||
if recorder.Code != http.StatusOK {
|
||||
t.Errorf("WaitContainer: wrong status. Want %d. Got %d.", http.StatusOK, recorder.Code)
|
||||
}
|
||||
expected := `{"StatusCode":63}` + "\n"
|
||||
if body := recorder.Body.String(); body != expected {
|
||||
t.Errorf("WaitContainer: wrong body. Want %q. Got %q.", expected, body)
|
||||
}
|
||||
@ -659,70 +838,33 @@ func TestRemoveImageByName(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPrepareFailure(t *testing.T) {
|
||||
server := DockerServer{failures: make(map[string]FailureSpec)}
|
||||
server := DockerServer{failures: make(map[string]string)}
|
||||
server.buildMuxer()
|
||||
errorId := "my_error"
|
||||
failure := FailureSpec{UrlRegex: "containers/json"}
|
||||
server.PrepareFailure(errorId, failure)
|
||||
errorID := "my_error"
|
||||
server.PrepareFailure(errorID, "containers/json")
|
||||
recorder := httptest.NewRecorder()
|
||||
request, _ := http.NewRequest("GET", "/containers/json?all=1", nil)
|
||||
server.ServeHTTP(recorder, request)
|
||||
if recorder.Code != http.StatusBadRequest {
|
||||
t.Errorf("PrepareFailure: wrong status. Want %d. Got %d.", http.StatusBadRequest, recorder.Code)
|
||||
}
|
||||
if recorder.Body.String() != errorId+"\n" {
|
||||
t.Errorf("PrepareFailure: wrong message. Want %s. Got %s.", errorId, recorder.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrepareFailureUsingContainerPath(t *testing.T) {
|
||||
server := DockerServer{failures: make(map[string]FailureSpec)}
|
||||
addContainers(&server, 1)
|
||||
server.buildMuxer()
|
||||
errorId := "my_path_error"
|
||||
failure := FailureSpec{UrlRegex: "containers/.*?/start", ContainerPath: "ls"}
|
||||
server.PrepareFailure(errorId, failure)
|
||||
recorder := httptest.NewRecorder()
|
||||
path := fmt.Sprintf("/containers/%s/start", server.containers[0].ID)
|
||||
request, _ := http.NewRequest("POST", path, nil)
|
||||
server.ServeHTTP(recorder, request)
|
||||
if recorder.Code != http.StatusBadRequest {
|
||||
t.Errorf("TestPrepareFailureUsingContainerPath: wrong status. Want %d. Got %d.", http.StatusBadRequest, recorder.Code)
|
||||
}
|
||||
if recorder.Body.String() != errorId+"\n" {
|
||||
t.Errorf("TestPrepareFailureUsingContainerPath: wrong message. Want %s. Got %s.", errorId, recorder.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrepareFailureUsingContainerPathWithWrongPath(t *testing.T) {
|
||||
server := DockerServer{failures: make(map[string]FailureSpec)}
|
||||
addContainers(&server, 1)
|
||||
server.buildMuxer()
|
||||
errorId := "my_path_error"
|
||||
failure := FailureSpec{UrlRegex: "containers/.*?/start", ContainerPath: "xxx"}
|
||||
server.PrepareFailure(errorId, failure)
|
||||
recorder := httptest.NewRecorder()
|
||||
path := fmt.Sprintf("/containers/%s/start", server.containers[0].ID)
|
||||
request, _ := http.NewRequest("POST", path, nil)
|
||||
server.ServeHTTP(recorder, request)
|
||||
if recorder.Code != http.StatusOK {
|
||||
t.Errorf("StartContainer: wrong status code. Want %d. Got %d.", http.StatusOK, recorder.Code)
|
||||
if recorder.Body.String() != errorID+"\n" {
|
||||
t.Errorf("PrepareFailure: wrong message. Want %s. Got %s.", errorID, recorder.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveFailure(t *testing.T) {
|
||||
server := DockerServer{failures: make(map[string]FailureSpec)}
|
||||
server := DockerServer{failures: make(map[string]string)}
|
||||
server.buildMuxer()
|
||||
errorId := "my_error"
|
||||
failure := FailureSpec{UrlRegex: "containers/json"}
|
||||
server.PrepareFailure(errorId, failure)
|
||||
errorID := "my_error"
|
||||
server.PrepareFailure(errorID, "containers/json")
|
||||
recorder := httptest.NewRecorder()
|
||||
request, _ := http.NewRequest("GET", "/containers/json?all=1", nil)
|
||||
server.ServeHTTP(recorder, request)
|
||||
if recorder.Code != http.StatusBadRequest {
|
||||
t.Errorf("PrepareFailure: wrong status. Want %d. Got %d.", http.StatusBadRequest, recorder.Code)
|
||||
}
|
||||
server.ResetFailure(errorId)
|
||||
server.ResetFailure(errorID)
|
||||
recorder = httptest.NewRecorder()
|
||||
request, _ = http.NewRequest("GET", "/containers/json?all=1", nil)
|
||||
server.ServeHTTP(recorder, request)
|
||||
@ -731,6 +873,34 @@ func TestRemoveFailure(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMutateContainer(t *testing.T) {
|
||||
server := DockerServer{failures: make(map[string]string)}
|
||||
server.buildMuxer()
|
||||
server.containers = append(server.containers, &docker.Container{ID: "id123"})
|
||||
state := docker.State{Running: false, ExitCode: 1}
|
||||
err := server.MutateContainer("id123", state)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(server.containers[0].State, state) {
|
||||
t.Errorf("Wrong state after mutation.\nWant %#v.\nGot %#v.",
|
||||
state, server.containers[0].State)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMutateContainerNotFound(t *testing.T) {
|
||||
server := DockerServer{failures: make(map[string]string)}
|
||||
server.buildMuxer()
|
||||
state := docker.State{Running: false, ExitCode: 1}
|
||||
err := server.MutateContainer("id123", state)
|
||||
if err == nil {
|
||||
t.Error("Unexpected <nil> error")
|
||||
}
|
||||
if err.Error() != "container not found" {
|
||||
t.Errorf("wrong error message. Want %q. Got %q.", "container not found", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildImageWithContentTypeTar(t *testing.T) {
|
||||
server := DockerServer{imgIDs: make(map[string]string)}
|
||||
imageName := "teste"
|
||||
@ -762,3 +932,16 @@ func TestBuildImageWithRemoteDockerfile(t *testing.T) {
|
||||
t.Errorf("BuildImage: image %s not builded", imageName)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPing(t *testing.T) {
|
||||
server := DockerServer{}
|
||||
recorder := httptest.NewRecorder()
|
||||
request, _ := http.NewRequest("GET", "/_ping", nil)
|
||||
server.pingDocker(recorder, request)
|
||||
if recorder.Body.String() != "" {
|
||||
t.Errorf("Ping: Unexpected body: %s", recorder.Body.String())
|
||||
}
|
||||
if recorder.Code != http.StatusOK {
|
||||
t.Errorf("Ping: Expected code %d, got: %d", http.StatusOK, recorder.Code)
|
||||
}
|
||||
}
|
||||
|
@ -87,9 +87,12 @@ func StdCopy(dstout, dsterr io.Writer, src io.Reader) (written int64, err error)
|
||||
var nr2 int
|
||||
nr2, er = src.Read(buf[nr:])
|
||||
if er == io.EOF {
|
||||
return written, nil
|
||||
}
|
||||
if er != nil {
|
||||
if nr < StdWriterPrefixLen && nr2 < StdWriterPrefixLen {
|
||||
return written, nil
|
||||
}
|
||||
nr += nr2
|
||||
break
|
||||
} else if er != nil {
|
||||
return 0, er
|
||||
}
|
||||
nr += nr2
|
||||
@ -117,7 +120,7 @@ func StdCopy(dstout, dsterr io.Writer, src io.Reader) (written int64, err error)
|
||||
// Extend it if necessary.
|
||||
if frameSize+StdWriterPrefixLen > bufLen {
|
||||
Debugf("Extending buffer cap.")
|
||||
buf = append(buf, make([]byte, frameSize-len(buf)+1)...)
|
||||
buf = append(buf, make([]byte, frameSize+StdWriterPrefixLen-len(buf)+1)...)
|
||||
bufLen = len(buf)
|
||||
}
|
||||
|
||||
@ -126,9 +129,12 @@ func StdCopy(dstout, dsterr io.Writer, src io.Reader) (written int64, err error)
|
||||
var nr2 int
|
||||
nr2, er = src.Read(buf[nr:])
|
||||
if er == io.EOF {
|
||||
return written, nil
|
||||
}
|
||||
if er != nil {
|
||||
if nr == 0 {
|
||||
return written, nil
|
||||
}
|
||||
nr += nr2
|
||||
break
|
||||
} else if er != nil {
|
||||
Debugf("Error reading frame: %s", er)
|
||||
return 0, er
|
||||
}
|
||||
@ -136,7 +142,11 @@ func StdCopy(dstout, dsterr io.Writer, src io.Reader) (written int64, err error)
|
||||
}
|
||||
|
||||
// Write the retrieved frame (without header)
|
||||
nw, ew = out.Write(buf[StdWriterPrefixLen : frameSize+StdWriterPrefixLen])
|
||||
bound := frameSize + StdWriterPrefixLen
|
||||
if bound > nr {
|
||||
bound = nr
|
||||
}
|
||||
nw, ew = out.Write(buf[StdWriterPrefixLen:bound])
|
||||
if nw > 0 {
|
||||
written += int64(nw)
|
||||
}
|
||||
@ -147,7 +157,7 @@ func StdCopy(dstout, dsterr io.Writer, src io.Reader) (written int64, err error)
|
||||
// If the frame has not been fully written: error
|
||||
if nw != frameSize {
|
||||
Debugf("Error Short Write: (%d on %d)", nw, frameSize)
|
||||
return 0, io.ErrShortWrite
|
||||
return written, io.ErrShortWrite
|
||||
}
|
||||
|
||||
// Move the rest of the buffer to the beginning
|
||||
|
217
third_party/src/github.com/fsouza/go-dockerclient/utils/stdcopy_test.go
vendored
Normal file
217
third_party/src/github.com/fsouza/go-dockerclient/utils/stdcopy_test.go
vendored
Normal file
@ -0,0 +1,217 @@
|
||||
// Copyright 2014 go-dockerclient authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the DOCKER-LICENSE file.
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"strings"
|
||||
"testing"
|
||||
"testing/iotest"
|
||||
)
|
||||
|
||||
type errorWriter struct {
|
||||
}
|
||||
|
||||
func (errorWriter) Write([]byte) (int, error) {
|
||||
return 0, errors.New("something went wrong")
|
||||
}
|
||||
|
||||
func TestStdCopy(t *testing.T) {
|
||||
var input, stdout, stderr bytes.Buffer
|
||||
input.Write([]byte{2, 0, 0, 0, 0, 0, 0, 19})
|
||||
input.Write([]byte("something happened!"))
|
||||
input.Write([]byte{1, 0, 0, 0, 0, 0, 0, 12})
|
||||
input.Write([]byte("just kidding"))
|
||||
input.Write([]byte{0, 0, 0, 0, 0, 0, 0, 6})
|
||||
input.Write([]byte("\nyeah!"))
|
||||
n, err := StdCopy(&stdout, &stderr, &input)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if expected := int64(19 + 12 + 6); n != expected {
|
||||
t.Errorf("Wrong number of bytes. Want %d. Got %d.", expected, n)
|
||||
}
|
||||
if got := stderr.String(); got != "something happened!" {
|
||||
t.Errorf("StdCopy: wrong stderr. Want %q. Got %q.", "something happened!", got)
|
||||
}
|
||||
if got := stdout.String(); got != "just kidding\nyeah!" {
|
||||
t.Errorf("StdCopy: wrong stdout. Want %q. Got %q.", "just kidding\nyeah!", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStdCopyStress(t *testing.T) {
|
||||
var input, stdout, stderr bytes.Buffer
|
||||
value := strings.Repeat("something ", 4096)
|
||||
writer := NewStdWriter(&input, Stdout)
|
||||
writer.Write([]byte(value))
|
||||
n, err := StdCopy(&stdout, &stderr, &input)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if n != 40960 {
|
||||
t.Errorf("Wrong number of bytes. Want 40960. Got %d.", n)
|
||||
}
|
||||
if got := stderr.String(); got != "" {
|
||||
t.Errorf("StdCopy: wrong stderr. Want empty string. Got %q", got)
|
||||
}
|
||||
if got := stdout.String(); got != value {
|
||||
t.Errorf("StdCopy: wrong stdout. Want %q. Got %q", value, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStdCopyInvalidStdHeader(t *testing.T) {
|
||||
var input, stdout, stderr bytes.Buffer
|
||||
input.Write([]byte{3, 0, 0, 0, 0, 0, 0, 19})
|
||||
n, err := StdCopy(&stdout, &stderr, &input)
|
||||
if n != 0 {
|
||||
t.Errorf("StdCopy: wrong number of bytes. Want 0. Got %d", n)
|
||||
}
|
||||
if err != ErrInvalidStdHeader {
|
||||
t.Errorf("StdCopy: wrong error. Want ErrInvalidStdHeader. Got %#v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStdCopyBigFrame(t *testing.T) {
|
||||
var input, stdout, stderr bytes.Buffer
|
||||
input.Write([]byte{2, 0, 0, 0, 0, 0, 0, 18})
|
||||
input.Write([]byte("something happened!"))
|
||||
n, err := StdCopy(&stdout, &stderr, &input)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if expected := int64(18); n != expected {
|
||||
t.Errorf("Wrong number of bytes. Want %d. Got %d.", expected, n)
|
||||
}
|
||||
if got := stderr.String(); got != "something happened" {
|
||||
t.Errorf("StdCopy: wrong stderr. Want %q. Got %q.", "something happened", got)
|
||||
}
|
||||
if got := stdout.String(); got != "" {
|
||||
t.Errorf("StdCopy: wrong stdout. Want %q. Got %q.", "", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStdCopySmallFrame(t *testing.T) {
|
||||
var input, stdout, stderr bytes.Buffer
|
||||
input.Write([]byte{2, 0, 0, 0, 0, 0, 0, 20})
|
||||
input.Write([]byte("something happened!"))
|
||||
n, err := StdCopy(&stdout, &stderr, &input)
|
||||
if err != io.ErrShortWrite {
|
||||
t.Errorf("StdCopy: wrong error. Want ShortWrite. Got %#v", err)
|
||||
}
|
||||
if expected := int64(19); n != expected {
|
||||
t.Errorf("Wrong number of bytes. Want %d. Got %d.", expected, n)
|
||||
}
|
||||
if got := stderr.String(); got != "something happened!" {
|
||||
t.Errorf("StdCopy: wrong stderr. Want %q. Got %q.", "something happened", got)
|
||||
}
|
||||
if got := stdout.String(); got != "" {
|
||||
t.Errorf("StdCopy: wrong stdout. Want %q. Got %q.", "", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStdCopyEmpty(t *testing.T) {
|
||||
var input, stdout, stderr bytes.Buffer
|
||||
n, err := StdCopy(&stdout, &stderr, &input)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if n != 0 {
|
||||
t.Errorf("StdCopy: wrong number of bytes. Want 0. Got %d.", n)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStdCopyCorruptedHeader(t *testing.T) {
|
||||
var input, stdout, stderr bytes.Buffer
|
||||
input.Write([]byte{2, 0, 0, 0, 0})
|
||||
n, err := StdCopy(&stdout, &stderr, &input)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if n != 0 {
|
||||
t.Errorf("StdCopy: wrong number of bytes. Want 0. Got %d.", n)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStdCopyTruncateWriter(t *testing.T) {
|
||||
var input, stdout, stderr bytes.Buffer
|
||||
input.Write([]byte{2, 0, 0, 0, 0, 0, 0, 19})
|
||||
input.Write([]byte("something happened!"))
|
||||
n, err := StdCopy(&stdout, iotest.TruncateWriter(&stderr, 7), &input)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if expected := int64(19); n != expected {
|
||||
t.Errorf("Wrong number of bytes. Want %d. Got %d.", expected, n)
|
||||
}
|
||||
if got := stderr.String(); got != "somethi" {
|
||||
t.Errorf("StdCopy: wrong stderr. Want %q. Got %q.", "somethi", got)
|
||||
}
|
||||
if got := stdout.String(); got != "" {
|
||||
t.Errorf("StdCopy: wrong stdout. Want %q. Got %q.", "", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStdCopyHeaderOnly(t *testing.T) {
|
||||
var input, stdout, stderr bytes.Buffer
|
||||
input.Write([]byte{2, 0, 0, 0, 0, 0, 0, 19})
|
||||
n, err := StdCopy(&stdout, iotest.TruncateWriter(&stderr, 7), &input)
|
||||
if err != io.ErrShortWrite {
|
||||
t.Errorf("StdCopy: wrong error. Want ShortWrite. Got %#v", err)
|
||||
}
|
||||
if n != 0 {
|
||||
t.Errorf("Wrong number of bytes. Want 0. Got %d.", n)
|
||||
}
|
||||
if got := stderr.String(); got != "" {
|
||||
t.Errorf("StdCopy: wrong stderr. Want %q. Got %q.", "", got)
|
||||
}
|
||||
if got := stdout.String(); got != "" {
|
||||
t.Errorf("StdCopy: wrong stdout. Want %q. Got %q.", "", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStdCopyDataErrReader(t *testing.T) {
|
||||
var input, stdout, stderr bytes.Buffer
|
||||
input.Write([]byte{2, 0, 0, 0, 0, 0, 0, 19})
|
||||
input.Write([]byte("something happened!"))
|
||||
n, err := StdCopy(&stdout, &stderr, iotest.DataErrReader(&input))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if expected := int64(19); n != expected {
|
||||
t.Errorf("Wrong number of bytes. Want %d. Got %d.", expected, n)
|
||||
}
|
||||
if got := stderr.String(); got != "something happened!" {
|
||||
t.Errorf("StdCopy: wrong stderr. Want %q. Got %q.", "something happened!", got)
|
||||
}
|
||||
if got := stdout.String(); got != "" {
|
||||
t.Errorf("StdCopy: wrong stdout. Want %q. Got %q.", "", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStdCopyTimeoutReader(t *testing.T) {
|
||||
var input, stdout, stderr bytes.Buffer
|
||||
input.Write([]byte{2, 0, 0, 0, 0, 0, 0, 19})
|
||||
input.Write([]byte("something happened!"))
|
||||
_, err := StdCopy(&stdout, &stderr, iotest.TimeoutReader(&input))
|
||||
if err != iotest.ErrTimeout {
|
||||
t.Errorf("StdCopy: wrong error. Want ErrTimeout. Got %#v.", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStdCopyWriteError(t *testing.T) {
|
||||
var input bytes.Buffer
|
||||
input.Write([]byte{2, 0, 0, 0, 0, 0, 0, 19})
|
||||
input.Write([]byte("something happened!"))
|
||||
var stdout, stderr errorWriter
|
||||
n, err := StdCopy(stdout, stderr, &input)
|
||||
if err.Error() != "something went wrong" {
|
||||
t.Errorf("StdCopy: wrong error. Want %q. Got %q", "something went wrong", err)
|
||||
}
|
||||
if n != 0 {
|
||||
t.Errorf("StdCopy: wrong number of bytes. Want 0. Got %d.", n)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user