Cleanup pkg/jsonmessage progress tests

Signed-off-by: Daniel Nephin <dnephin@docker.com>
This commit is contained in:
Daniel Nephin 2017-12-29 15:13:13 -05:00
parent c9e52bd0da
commit 7d8815ea70
3 changed files with 132 additions and 93 deletions

View file

@ -40,21 +40,17 @@ type JSONProgress struct {
// If true, don't show xB/yB
HideCounts bool `json:"hidecounts,omitempty"`
Units string `json:"units,omitempty"`
nowFunc func() time.Time
winSize int
}
func (p *JSONProgress) String() string {
var (
width = 200
width = p.width()
pbBox string
numbersBox string
timeLeftBox string
)
ws, err := term.GetWinsize(p.terminalFd)
if err == nil {
width = int(ws.Width)
}
if p.Current <= 0 && p.Total <= 0 {
return ""
}
@ -103,7 +99,7 @@ func (p *JSONProgress) String() string {
}
if p.Current > 0 && p.Start > 0 && percentage < 50 {
fromStart := time.Now().UTC().Sub(time.Unix(p.Start, 0))
fromStart := p.now().Sub(time.Unix(p.Start, 0))
perEntry := fromStart / time.Duration(p.Current)
left := time.Duration(p.Total-p.Current) * perEntry
left = (left / time.Second) * time.Second
@ -115,6 +111,28 @@ func (p *JSONProgress) String() string {
return pbBox + numbersBox + timeLeftBox
}
// shim for testing
func (p *JSONProgress) now() time.Time {
if p.nowFunc == nil {
p.nowFunc = func() time.Time {
return time.Now().UTC()
}
}
return p.nowFunc()
}
// shim for testing
func (p *JSONProgress) width() int {
if p.winSize != 0 {
return p.winSize
}
ws, err := term.GetWinsize(p.terminalFd)
if err == nil {
return int(ws.Width)
}
return 200
}
// JSONMessage defines a message struct. It describes
// the created time, where it from, status, ID of the
// message. It's used for docker events.

View file

@ -15,84 +15,102 @@ import (
func TestError(t *testing.T) {
je := JSONError{404, "Not found"}
if je.Error() != "Not found" {
t.Fatalf("Expected 'Not found' got '%s'", je.Error())
}
assert.Assert(t, is.Error(&je, "Not found"))
}
func TestProgress(t *testing.T) {
termsz, err := term.GetWinsize(0)
if err != nil {
// we can safely ignore the err here
termsz = nil
}
jp := JSONProgress{}
if jp.String() != "" {
t.Fatalf("Expected empty string, got '%s'", jp.String())
func TestProgressString(t *testing.T) {
type expected struct {
short string
long string
}
expected := " 1B"
jp2 := JSONProgress{Current: 1}
if jp2.String() != expected {
t.Fatalf("Expected %q, got %q", expected, jp2.String())
shortAndLong := func(short, long string) expected {
return expected{short: short, long: long}
}
expectedStart := "[==========> ] 20B/100B"
if termsz != nil && termsz.Width <= 110 {
expectedStart = " 20B/100B"
}
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())
start := time.Date(2017, 12, 3, 15, 10, 1, 0, time.UTC)
timeAfter := func(delta time.Duration) func() time.Time {
return func() time.Time {
return start.Add(delta)
}
}
expected = "[=========================> ] 50B/100B"
if termsz != nil && termsz.Width <= 110 {
expected = " 50B/100B"
}
jp4 := JSONProgress{Current: 50, Total: 100}
if jp4.String() != expected {
t.Fatalf("Expected %q, got %q", expected, jp4.String())
var testcases = []struct {
name string
progress JSONProgress
expected expected
}{
{
name: "no progress",
},
{
name: "progress 1",
progress: JSONProgress{Current: 1},
expected: shortAndLong(" 1B", " 1B"),
},
{
name: "some progress with a start time",
progress: JSONProgress{
Current: 20,
Total: 100,
Start: start.Unix(),
nowFunc: timeAfter(time.Second),
},
expected: shortAndLong(
" 20B/100B 4s",
"[==========> ] 20B/100B 4s",
),
},
{
name: "some progress without a start time",
progress: JSONProgress{Current: 50, Total: 100},
expected: shortAndLong(
" 50B/100B",
"[=========================> ] 50B/100B",
),
},
{
name: "current more than total is not negative gh#7136",
progress: JSONProgress{Current: 50, Total: 40},
expected: shortAndLong(
" 50B",
"[==================================================>] 50B",
),
},
{
name: "with units",
progress: JSONProgress{Current: 50, Total: 100, Units: "units"},
expected: shortAndLong(
"50/100 units",
"[=========================> ] 50/100 units",
),
},
{
name: "current more than total with units is not negative ",
progress: JSONProgress{Current: 50, Total: 40, Units: "units"},
expected: shortAndLong(
"50 units",
"[==================================================>] 50 units",
),
},
{
name: "hide counts",
progress: JSONProgress{Current: 50, Total: 100, HideCounts: true},
expected: shortAndLong(
"",
"[=========================> ] ",
),
},
}
// this number can't be negative gh#7136
expected = "[==================================================>] 50B"
if termsz != nil && termsz.Width <= 110 {
expected = " 50B"
}
jp5 := JSONProgress{Current: 50, Total: 40}
if jp5.String() != expected {
t.Fatalf("Expected %q, got %q", expected, jp5.String())
}
for _, testcase := range testcases {
t.Run(testcase.name, func(t *testing.T) {
testcase.progress.winSize = 100
assert.Equal(t, testcase.progress.String(), testcase.expected.short)
expected = "[=========================> ] 50/100 units"
if termsz != nil && termsz.Width <= 110 {
expected = " 50/100 units"
}
jp6 := JSONProgress{Current: 50, Total: 100, Units: "units"}
if jp6.String() != expected {
t.Fatalf("Expected %q, got %q", expected, jp6.String())
}
// this number can't be negative
expected = "[==================================================>] 50 units"
if termsz != nil && termsz.Width <= 110 {
expected = " 50 units"
}
jp7 := JSONProgress{Current: 50, Total: 40, Units: "units"}
if jp7.String() != expected {
t.Fatalf("Expected %q, got %q", expected, jp7.String())
}
expected = "[=========================> ] "
if termsz != nil && termsz.Width <= 110 {
expected = ""
}
jp8 := JSONProgress{Current: 50, Total: 100, HideCounts: true}
if jp8.String() != expected {
t.Fatalf("Expected %q, got %q", expected, jp8.String())
testcase.progress.winSize = 200
assert.Equal(t, testcase.progress.String(), testcase.expected.long)
})
}
}

View file

@ -8,6 +8,8 @@ import (
"testing"
"github.com/docker/docker/pkg/jsonmessage"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
)
@ -58,30 +60,31 @@ func TestJsonProgressFormatterFormatProgress(t *testing.T) {
Total: 30,
Start: 1,
}
res := sf.formatProgress("id", "action", jsonProgress, &AuxFormatter{Writer: &bytes.Buffer{}})
aux := "aux message"
res := sf.formatProgress("id", "action", jsonProgress, aux)
msg := &jsonmessage.JSONMessage{}
assert.NilError(t, json.Unmarshal(res, msg))
assert.Check(t, is.Equal("id", msg.ID))
assert.Check(t, is.Equal("action", msg.Status))
// jsonProgress will always be in the format of:
// [=========================> ] 15B/30B 412910h51m30s
// The last entry '404933h7m11s' is the timeLeftBox.
// However, the timeLeftBox field may change as jsonProgress.String() depends on time.Now().
// Therefore, we have to strip the timeLeftBox from the strings to do the comparison.
// Compare the jsonProgress strings before the timeLeftBox
expectedProgress := "[=========================> ] 15B/30B"
// if terminal column is <= 110, expectedProgressShort is expected.
expectedProgressShort := " 15B/30B"
if !(strings.HasPrefix(msg.ProgressMessage, expectedProgress) ||
strings.HasPrefix(msg.ProgressMessage, expectedProgressShort)) {
t.Fatalf("ProgressMessage without the timeLeftBox must be %s or %s, got: %s",
expectedProgress, expectedProgressShort, msg.ProgressMessage)
rawAux := json.RawMessage(`"` + aux + `"`)
expected := &jsonmessage.JSONMessage{
ID: "id",
Status: "action",
Aux: &rawAux,
Progress: jsonProgress,
}
assert.DeepEqual(t, msg, expected, cmpJSONMessageOpt())
}
assert.Check(t, is.DeepEqual(jsonProgress, msg.Progress))
func cmpJSONMessageOpt() cmp.Option {
progressMessagePath := func(path cmp.Path) bool {
return path.String() == "ProgressMessage"
}
return cmp.Options{
cmpopts.IgnoreUnexported(jsonmessage.JSONProgress{}),
// Ignore deprecated property that is a derivative of Progress
cmp.FilterPath(progressMessagePath, cmp.Ignore()),
}
}
func TestJsonProgressFormatterFormatStatus(t *testing.T) {