2015-03-17 22:18:41 -04:00
|
|
|
package jsonmessage
|
2013-11-28 19:28:31 -05:00
|
|
|
|
|
|
|
import (
|
2015-06-02 08:29:31 -04:00
|
|
|
"bytes"
|
|
|
|
"fmt"
|
2016-11-09 12:55:11 -05:00
|
|
|
"os"
|
2015-08-11 16:47:08 -04:00
|
|
|
"strings"
|
2013-11-28 19:28:31 -05:00
|
|
|
"testing"
|
2015-06-02 08:29:31 -04:00
|
|
|
"time"
|
|
|
|
|
2015-12-15 14:49:41 -05:00
|
|
|
"github.com/docker/docker/pkg/jsonlog"
|
2015-06-02 08:29:31 -04:00
|
|
|
"github.com/docker/docker/pkg/term"
|
2013-11-28 19:28:31 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestError(t *testing.T) {
|
|
|
|
je := JSONError{404, "Not found"}
|
|
|
|
if je.Error() != "Not found" {
|
|
|
|
t.Fatalf("Expected 'Not found' got '%s'", je.Error())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestProgress(t *testing.T) {
|
2016-05-31 00:12:25 -04:00
|
|
|
termsz, err := term.GetWinsize(0)
|
|
|
|
if err != nil {
|
|
|
|
// we can safely ignore the err here
|
|
|
|
termsz = nil
|
|
|
|
}
|
2013-12-02 14:53:04 -05:00
|
|
|
jp := JSONProgress{}
|
2013-11-28 19:28:31 -05:00
|
|
|
if jp.String() != "" {
|
|
|
|
t.Fatalf("Expected empty string, got '%s'", jp.String())
|
|
|
|
}
|
|
|
|
|
2017-02-07 15:58:56 -05:00
|
|
|
expected := " 1B"
|
2013-12-02 14:53:04 -05:00
|
|
|
jp2 := JSONProgress{Current: 1}
|
2014-07-28 14:43:28 -04:00
|
|
|
if jp2.String() != expected {
|
|
|
|
t.Fatalf("Expected %q, got %q", expected, jp2.String())
|
2013-12-02 14:53:04 -05:00
|
|
|
}
|
|
|
|
|
2017-02-07 15:58:56 -05:00
|
|
|
expectedStart := "[==========> ] 20B/100B"
|
2016-05-31 00:12:25 -04:00
|
|
|
if termsz != nil && termsz.Width <= 110 {
|
2017-02-07 15:58:56 -05:00
|
|
|
expectedStart = " 20B/100B"
|
2016-05-31 00:12:25 -04:00
|
|
|
}
|
2015-06-02 08:29:31 -04:00
|
|
|
jp3 := JSONProgress{Current: 20, Total: 100, Start: time.Now().Unix()}
|
|
|
|
// Just look at the start of the string
|
|
|
|
// (the remaining time is really hard to test -_-)
|
|
|
|
if jp3.String()[:len(expectedStart)] != expectedStart {
|
|
|
|
t.Fatalf("Expected to start with %q, got %q", expectedStart, jp3.String())
|
2014-07-28 14:43:28 -04:00
|
|
|
}
|
|
|
|
|
2017-02-07 15:58:56 -05:00
|
|
|
expected = "[=========================> ] 50B/100B"
|
2016-05-31 00:12:25 -04:00
|
|
|
if termsz != nil && termsz.Width <= 110 {
|
2017-02-07 15:58:56 -05:00
|
|
|
expected = " 50B/100B"
|
2016-05-31 00:12:25 -04:00
|
|
|
}
|
2015-06-02 08:29:31 -04:00
|
|
|
jp4 := JSONProgress{Current: 50, Total: 100}
|
2014-07-28 14:43:28 -04:00
|
|
|
if jp4.String() != expected {
|
|
|
|
t.Fatalf("Expected %q, got %q", expected, jp4.String())
|
2013-11-28 19:28:31 -05:00
|
|
|
}
|
2015-06-02 08:29:31 -04:00
|
|
|
|
|
|
|
// this number can't be negative gh#7136
|
2017-02-07 15:58:56 -05:00
|
|
|
expected = "[==================================================>] 50B"
|
2016-05-31 00:12:25 -04:00
|
|
|
if termsz != nil && termsz.Width <= 110 {
|
2017-02-07 15:58:56 -05:00
|
|
|
expected = " 50B"
|
2016-05-31 00:12:25 -04:00
|
|
|
}
|
2015-06-02 08:29:31 -04:00
|
|
|
jp5 := JSONProgress{Current: 50, Total: 40}
|
|
|
|
if jp5.String() != expected {
|
|
|
|
t.Fatalf("Expected %q, got %q", expected, jp5.String())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestJSONMessageDisplay(t *testing.T) {
|
2015-09-15 15:33:11 -04:00
|
|
|
now := time.Now()
|
2015-06-02 08:29:31 -04:00
|
|
|
messages := map[JSONMessage][]string{
|
|
|
|
// Empty
|
|
|
|
JSONMessage{}: {"\n", "\n"},
|
|
|
|
// Status
|
|
|
|
JSONMessage{
|
|
|
|
Status: "status",
|
|
|
|
}: {
|
|
|
|
"status\n",
|
|
|
|
"status\n",
|
|
|
|
},
|
|
|
|
// General
|
|
|
|
JSONMessage{
|
2015-09-15 15:33:11 -04:00
|
|
|
Time: now.Unix(),
|
2015-06-02 08:29:31 -04:00
|
|
|
ID: "ID",
|
|
|
|
From: "From",
|
|
|
|
Status: "status",
|
|
|
|
}: {
|
2015-12-15 14:49:41 -05:00
|
|
|
fmt.Sprintf("%v ID: (from From) status\n", time.Unix(now.Unix(), 0).Format(jsonlog.RFC3339NanoFixed)),
|
|
|
|
fmt.Sprintf("%v ID: (from From) status\n", time.Unix(now.Unix(), 0).Format(jsonlog.RFC3339NanoFixed)),
|
2015-09-15 15:33:11 -04:00
|
|
|
},
|
|
|
|
// General, with nano precision time
|
|
|
|
JSONMessage{
|
|
|
|
TimeNano: now.UnixNano(),
|
|
|
|
ID: "ID",
|
|
|
|
From: "From",
|
|
|
|
Status: "status",
|
|
|
|
}: {
|
2015-12-15 14:49:41 -05:00
|
|
|
fmt.Sprintf("%v ID: (from From) status\n", time.Unix(0, now.UnixNano()).Format(jsonlog.RFC3339NanoFixed)),
|
|
|
|
fmt.Sprintf("%v ID: (from From) status\n", time.Unix(0, now.UnixNano()).Format(jsonlog.RFC3339NanoFixed)),
|
2015-09-15 15:33:11 -04:00
|
|
|
},
|
|
|
|
// General, with both times Nano is preferred
|
|
|
|
JSONMessage{
|
|
|
|
Time: now.Unix(),
|
|
|
|
TimeNano: now.UnixNano(),
|
|
|
|
ID: "ID",
|
|
|
|
From: "From",
|
|
|
|
Status: "status",
|
|
|
|
}: {
|
2015-12-15 14:49:41 -05:00
|
|
|
fmt.Sprintf("%v ID: (from From) status\n", time.Unix(0, now.UnixNano()).Format(jsonlog.RFC3339NanoFixed)),
|
|
|
|
fmt.Sprintf("%v ID: (from From) status\n", time.Unix(0, now.UnixNano()).Format(jsonlog.RFC3339NanoFixed)),
|
2015-06-02 08:29:31 -04:00
|
|
|
},
|
|
|
|
// Stream over status
|
|
|
|
JSONMessage{
|
|
|
|
Status: "status",
|
|
|
|
Stream: "stream",
|
|
|
|
}: {
|
|
|
|
"stream",
|
|
|
|
"stream",
|
|
|
|
},
|
|
|
|
// With progress message
|
|
|
|
JSONMessage{
|
|
|
|
Status: "status",
|
|
|
|
ProgressMessage: "progressMessage",
|
|
|
|
}: {
|
|
|
|
"status progressMessage",
|
|
|
|
"status progressMessage",
|
|
|
|
},
|
|
|
|
// With progress, stream empty
|
|
|
|
JSONMessage{
|
|
|
|
Status: "status",
|
|
|
|
Stream: "",
|
|
|
|
Progress: &JSONProgress{Current: 1},
|
|
|
|
}: {
|
|
|
|
"",
|
2017-02-07 15:58:56 -05:00
|
|
|
fmt.Sprintf("%c[1K%c[K\rstatus 1B\r", 27, 27),
|
2015-06-02 08:29:31 -04:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
// The tests :)
|
|
|
|
for jsonMessage, expectedMessages := range messages {
|
|
|
|
// Without terminal
|
|
|
|
data := bytes.NewBuffer([]byte{})
|
2016-11-09 12:55:11 -05:00
|
|
|
if err := jsonMessage.Display(data, nil); err != nil {
|
2015-06-02 08:29:31 -04:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if data.String() != expectedMessages[0] {
|
2016-11-11 06:13:36 -05:00
|
|
|
t.Fatalf("Expected %q,got %q", expectedMessages[0], data.String())
|
2015-06-02 08:29:31 -04:00
|
|
|
}
|
|
|
|
// With terminal
|
|
|
|
data = bytes.NewBuffer([]byte{})
|
2016-11-09 12:55:11 -05:00
|
|
|
if err := jsonMessage.Display(data, &noTermInfo{}); err != nil {
|
2015-06-02 08:29:31 -04:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if data.String() != expectedMessages[1] {
|
2016-11-11 06:13:36 -05:00
|
|
|
t.Fatalf("\nExpected %q\n got %q", expectedMessages[1], data.String())
|
2015-06-02 08:29:31 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test JSONMessage with an Error. It will return an error with the text as error, not the meaning of the HTTP code.
|
|
|
|
func TestJSONMessageDisplayWithJSONError(t *testing.T) {
|
|
|
|
data := bytes.NewBuffer([]byte{})
|
|
|
|
jsonMessage := JSONMessage{Error: &JSONError{404, "Can't find it"}}
|
|
|
|
|
2016-11-09 12:55:11 -05:00
|
|
|
err := jsonMessage.Display(data, &noTermInfo{})
|
2015-06-02 08:29:31 -04:00
|
|
|
if err == nil || err.Error() != "Can't find it" {
|
2016-11-11 06:07:04 -05:00
|
|
|
t.Fatalf("Expected a JSONError 404, got %q", err)
|
2015-06-02 08:29:31 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
jsonMessage = JSONMessage{Error: &JSONError{401, "Anything"}}
|
2016-11-09 12:55:11 -05:00
|
|
|
err = jsonMessage.Display(data, &noTermInfo{})
|
2015-06-02 08:29:31 -04:00
|
|
|
if err == nil || err.Error() != "Authentication is required." {
|
2016-11-11 06:07:04 -05:00
|
|
|
t.Fatalf("Expected an error \"Authentication is required.\", got %q", err)
|
2015-06-02 08:29:31 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestDisplayJSONMessagesStreamInvalidJSON(t *testing.T) {
|
|
|
|
var (
|
|
|
|
inFd uintptr
|
|
|
|
)
|
|
|
|
data := bytes.NewBuffer([]byte{})
|
|
|
|
reader := strings.NewReader("This is not a 'valid' JSON []")
|
|
|
|
inFd, _ = term.GetFdInfo(reader)
|
|
|
|
|
2015-12-21 18:02:44 -05:00
|
|
|
if err := DisplayJSONMessagesStream(reader, data, inFd, false, nil); err == nil && err.Error()[:17] != "invalid character" {
|
2016-11-11 06:07:04 -05:00
|
|
|
t.Fatalf("Should have thrown an error (invalid character in ..), got %q", err)
|
2015-06-02 08:29:31 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestDisplayJSONMessagesStream(t *testing.T) {
|
|
|
|
var (
|
|
|
|
inFd uintptr
|
|
|
|
)
|
|
|
|
|
|
|
|
messages := map[string][]string{
|
|
|
|
// empty string
|
|
|
|
"": {
|
|
|
|
"",
|
|
|
|
""},
|
|
|
|
// Without progress & ID
|
|
|
|
"{ \"status\": \"status\" }": {
|
|
|
|
"status\n",
|
|
|
|
"status\n",
|
|
|
|
},
|
|
|
|
// Without progress, with ID
|
|
|
|
"{ \"id\": \"ID\",\"status\": \"status\" }": {
|
|
|
|
"ID: status\n",
|
2016-11-09 11:51:18 -05:00
|
|
|
fmt.Sprintf("ID: status\n"),
|
2015-06-02 08:29:31 -04:00
|
|
|
},
|
|
|
|
// With progress
|
|
|
|
"{ \"id\": \"ID\", \"status\": \"status\", \"progress\": \"ProgressMessage\" }": {
|
|
|
|
"ID: status ProgressMessage",
|
2016-11-09 11:51:18 -05:00
|
|
|
fmt.Sprintf("\n%c[%dAID: status ProgressMessage%c[%dB", 27, 1, 27, 1),
|
2015-06-02 08:29:31 -04:00
|
|
|
},
|
|
|
|
// With progressDetail
|
|
|
|
"{ \"id\": \"ID\", \"status\": \"status\", \"progressDetail\": { \"Current\": 1} }": {
|
|
|
|
"", // progressbar is disabled in non-terminal
|
2017-02-07 15:58:56 -05:00
|
|
|
fmt.Sprintf("\n%c[%dA%c[1K%c[K\rID: status 1B\r%c[%dB", 27, 1, 27, 27, 27, 1),
|
2015-06-02 08:29:31 -04:00
|
|
|
},
|
|
|
|
}
|
2016-11-09 12:55:11 -05:00
|
|
|
|
|
|
|
// Use $TERM which is unlikely to exist, forcing DisplayJSONMessageStream to
|
|
|
|
// (hopefully) use &noTermInfo.
|
|
|
|
origTerm := os.Getenv("TERM")
|
|
|
|
os.Setenv("TERM", "xyzzy-non-existent-terminfo")
|
|
|
|
|
2015-06-02 08:29:31 -04:00
|
|
|
for jsonMessage, expectedMessages := range messages {
|
|
|
|
data := bytes.NewBuffer([]byte{})
|
|
|
|
reader := strings.NewReader(jsonMessage)
|
|
|
|
inFd, _ = term.GetFdInfo(reader)
|
|
|
|
|
|
|
|
// Without terminal
|
2015-12-21 18:02:44 -05:00
|
|
|
if err := DisplayJSONMessagesStream(reader, data, inFd, false, nil); err != nil {
|
2015-06-02 08:29:31 -04:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if data.String() != expectedMessages[0] {
|
2016-11-11 06:07:04 -05:00
|
|
|
t.Fatalf("Expected an %q, got %q", expectedMessages[0], data.String())
|
2015-06-02 08:29:31 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// With terminal
|
|
|
|
data = bytes.NewBuffer([]byte{})
|
|
|
|
reader = strings.NewReader(jsonMessage)
|
2015-12-21 18:02:44 -05:00
|
|
|
if err := DisplayJSONMessagesStream(reader, data, inFd, true, nil); err != nil {
|
2015-06-02 08:29:31 -04:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if data.String() != expectedMessages[1] {
|
2016-11-11 06:13:36 -05:00
|
|
|
t.Fatalf("\nExpected %q\n got %q", expectedMessages[1], data.String())
|
2015-06-02 08:29:31 -04:00
|
|
|
}
|
|
|
|
}
|
2016-11-09 12:55:11 -05:00
|
|
|
os.Setenv("TERM", origTerm)
|
2015-06-02 08:29:31 -04:00
|
|
|
|
2013-11-28 19:28:31 -05:00
|
|
|
}
|