mirror of
https://github.com/moby/moby.git
synced 2026-01-11 18:51:37 +00:00
The WithMockClient option was explicitly resetting the client's API version (see [1]), which differs from the regular client, which is initialized with the current API version used by the client (see [2]). This patch: - reduces the `WithMockClient` to only set the custom HTTP client, leaving other fields un-touched. - adds a test utility and updates tests to handle the API-version prefix - removes redundant uses of `WithVersion()` in tests; for most test-cases it was used to make sure a current API version is used that supports the feature being tested, but there was no test to verify the behavior for lower API versions, so we may as well test against "latest". [1]:5a582729d8/client/client_mock_test.go (L22-L36)[2]:5a582729d8/client/client.go (L167-L190)Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
178 lines
4.7 KiB
Go
178 lines
4.7 KiB
Go
package client
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
|
|
cerrdefs "github.com/containerd/errdefs"
|
|
"gotest.tools/v3/assert"
|
|
is "gotest.tools/v3/assert/cmp"
|
|
)
|
|
|
|
func TestContainerLogsNotFoundError(t *testing.T) {
|
|
client, err := NewClientWithOpts(
|
|
WithMockClient(errorMock(http.StatusNotFound, "Not found")),
|
|
)
|
|
assert.NilError(t, err)
|
|
|
|
_, err = client.ContainerLogs(context.Background(), "container_id", ContainerLogsOptions{})
|
|
assert.Check(t, is.ErrorType(err, cerrdefs.IsNotFound))
|
|
|
|
_, err = client.ContainerLogs(context.Background(), "", ContainerLogsOptions{})
|
|
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
|
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
|
|
|
_, err = client.ContainerLogs(context.Background(), " ", ContainerLogsOptions{})
|
|
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
|
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
|
}
|
|
|
|
func TestContainerLogsError(t *testing.T) {
|
|
client, err := NewClientWithOpts(
|
|
WithMockClient(errorMock(http.StatusInternalServerError, "Server error")),
|
|
)
|
|
assert.NilError(t, err)
|
|
|
|
_, err = client.ContainerLogs(context.Background(), "container_id", ContainerLogsOptions{})
|
|
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
|
|
|
_, err = client.ContainerLogs(context.Background(), "container_id", ContainerLogsOptions{
|
|
Since: "2006-01-02TZ",
|
|
})
|
|
assert.Check(t, is.ErrorContains(err, `parsing time "2006-01-02TZ"`))
|
|
_, err = client.ContainerLogs(context.Background(), "container_id", ContainerLogsOptions{
|
|
Until: "2006-01-02TZ",
|
|
})
|
|
assert.Check(t, is.ErrorContains(err, `parsing time "2006-01-02TZ"`))
|
|
}
|
|
|
|
func TestContainerLogs(t *testing.T) {
|
|
const expectedURL = "/containers/container_id/logs"
|
|
cases := []struct {
|
|
options ContainerLogsOptions
|
|
expectedQueryParams map[string]string
|
|
expectedError string
|
|
}{
|
|
{
|
|
expectedQueryParams: map[string]string{
|
|
"tail": "",
|
|
},
|
|
},
|
|
{
|
|
options: ContainerLogsOptions{
|
|
Tail: "any",
|
|
},
|
|
expectedQueryParams: map[string]string{
|
|
"tail": "any",
|
|
},
|
|
},
|
|
{
|
|
options: ContainerLogsOptions{
|
|
ShowStdout: true,
|
|
ShowStderr: true,
|
|
Timestamps: true,
|
|
Details: true,
|
|
Follow: true,
|
|
},
|
|
expectedQueryParams: map[string]string{
|
|
"tail": "",
|
|
"stdout": "1",
|
|
"stderr": "1",
|
|
"timestamps": "1",
|
|
"details": "1",
|
|
"follow": "1",
|
|
},
|
|
},
|
|
{
|
|
options: ContainerLogsOptions{
|
|
// timestamp is passed as-is
|
|
Since: "1136073600.000000001",
|
|
},
|
|
expectedQueryParams: map[string]string{
|
|
"tail": "",
|
|
"since": "1136073600.000000001",
|
|
},
|
|
},
|
|
{
|
|
options: ContainerLogsOptions{
|
|
// timestamp is passed as-is
|
|
Until: "1136073600.000000001",
|
|
},
|
|
expectedQueryParams: map[string]string{
|
|
"tail": "",
|
|
"until": "1136073600.000000001",
|
|
},
|
|
},
|
|
{
|
|
options: ContainerLogsOptions{
|
|
// invalid dates are not passed.
|
|
Since: "invalid value",
|
|
},
|
|
expectedError: `invalid value for "since": failed to parse value as time or duration: "invalid value"`,
|
|
},
|
|
{
|
|
options: ContainerLogsOptions{
|
|
// invalid dates are not passed.
|
|
Until: "invalid value",
|
|
},
|
|
expectedError: `invalid value for "until": failed to parse value as time or duration: "invalid value"`,
|
|
},
|
|
}
|
|
for _, logCase := range cases {
|
|
client, err := NewClientWithOpts(
|
|
WithMockClient(func(req *http.Request) (*http.Response, error) {
|
|
if err := assertRequest(req, http.MethodGet, expectedURL); err != nil {
|
|
return nil, err
|
|
}
|
|
// Check query parameters
|
|
query := req.URL.Query()
|
|
for key, expected := range logCase.expectedQueryParams {
|
|
actual := query.Get(key)
|
|
if actual != expected {
|
|
return nil, fmt.Errorf("%s not set in URL query properly. Expected '%s', got %s", key, expected, actual)
|
|
}
|
|
}
|
|
return &http.Response{
|
|
StatusCode: http.StatusOK,
|
|
Body: io.NopCloser(bytes.NewReader([]byte("response"))),
|
|
}, nil
|
|
}),
|
|
)
|
|
assert.NilError(t, err)
|
|
body, err := client.ContainerLogs(context.Background(), "container_id", logCase.options)
|
|
if logCase.expectedError != "" {
|
|
assert.Check(t, is.Error(err, logCase.expectedError))
|
|
continue
|
|
}
|
|
assert.NilError(t, err)
|
|
defer body.Close()
|
|
content, err := io.ReadAll(body)
|
|
assert.NilError(t, err)
|
|
assert.Check(t, is.Contains(string(content), "response"))
|
|
}
|
|
}
|
|
|
|
func ExampleClient_ContainerLogs_withTimeout() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
defer cancel()
|
|
|
|
client, _ := NewClientWithOpts(FromEnv)
|
|
reader, err := client.ContainerLogs(ctx, "container_id", ContainerLogsOptions{})
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
_, err = io.Copy(os.Stdout, reader)
|
|
if err != nil && !errors.Is(err, io.EOF) {
|
|
log.Fatal(err)
|
|
}
|
|
}
|