github.com/fabiokung/docker@v0.11.2-0.20170222101415-4534dcd49497/pkg/jsonmessage/jsonmessage_test.go (about)

     1  package jsonmessage
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"os"
     7  	"strings"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/docker/docker/pkg/jsonlog"
    12  	"github.com/docker/docker/pkg/term"
    13  )
    14  
    15  func TestError(t *testing.T) {
    16  	je := JSONError{404, "Not found"}
    17  	if je.Error() != "Not found" {
    18  		t.Fatalf("Expected 'Not found' got '%s'", je.Error())
    19  	}
    20  }
    21  
    22  func TestProgress(t *testing.T) {
    23  	termsz, err := term.GetWinsize(0)
    24  	if err != nil {
    25  		// we can safely ignore the err here
    26  		termsz = nil
    27  	}
    28  	jp := JSONProgress{}
    29  	if jp.String() != "" {
    30  		t.Fatalf("Expected empty string, got '%s'", jp.String())
    31  	}
    32  
    33  	expected := "      1B"
    34  	jp2 := JSONProgress{Current: 1}
    35  	if jp2.String() != expected {
    36  		t.Fatalf("Expected %q, got %q", expected, jp2.String())
    37  	}
    38  
    39  	expectedStart := "[==========>                                        ]      20B/100B"
    40  	if termsz != nil && termsz.Width <= 110 {
    41  		expectedStart = "    20B/100B"
    42  	}
    43  	jp3 := JSONProgress{Current: 20, Total: 100, Start: time.Now().Unix()}
    44  	// Just look at the start of the string
    45  	// (the remaining time is really hard to test -_-)
    46  	if jp3.String()[:len(expectedStart)] != expectedStart {
    47  		t.Fatalf("Expected to start with %q, got %q", expectedStart, jp3.String())
    48  	}
    49  
    50  	expected = "[=========================>                         ]      50B/100B"
    51  	if termsz != nil && termsz.Width <= 110 {
    52  		expected = "    50B/100B"
    53  	}
    54  	jp4 := JSONProgress{Current: 50, Total: 100}
    55  	if jp4.String() != expected {
    56  		t.Fatalf("Expected %q, got %q", expected, jp4.String())
    57  	}
    58  
    59  	// this number can't be negative gh#7136
    60  	expected = "[==================================================>]      50B"
    61  	if termsz != nil && termsz.Width <= 110 {
    62  		expected = "    50B"
    63  	}
    64  	jp5 := JSONProgress{Current: 50, Total: 40}
    65  	if jp5.String() != expected {
    66  		t.Fatalf("Expected %q, got %q", expected, jp5.String())
    67  	}
    68  }
    69  
    70  func TestJSONMessageDisplay(t *testing.T) {
    71  	now := time.Now()
    72  	messages := map[JSONMessage][]string{
    73  		// Empty
    74  		JSONMessage{}: {"\n", "\n"},
    75  		// Status
    76  		JSONMessage{
    77  			Status: "status",
    78  		}: {
    79  			"status\n",
    80  			"status\n",
    81  		},
    82  		// General
    83  		JSONMessage{
    84  			Time:   now.Unix(),
    85  			ID:     "ID",
    86  			From:   "From",
    87  			Status: "status",
    88  		}: {
    89  			fmt.Sprintf("%v ID: (from From) status\n", time.Unix(now.Unix(), 0).Format(jsonlog.RFC3339NanoFixed)),
    90  			fmt.Sprintf("%v ID: (from From) status\n", time.Unix(now.Unix(), 0).Format(jsonlog.RFC3339NanoFixed)),
    91  		},
    92  		// General, with nano precision time
    93  		JSONMessage{
    94  			TimeNano: now.UnixNano(),
    95  			ID:       "ID",
    96  			From:     "From",
    97  			Status:   "status",
    98  		}: {
    99  			fmt.Sprintf("%v ID: (from From) status\n", time.Unix(0, now.UnixNano()).Format(jsonlog.RFC3339NanoFixed)),
   100  			fmt.Sprintf("%v ID: (from From) status\n", time.Unix(0, now.UnixNano()).Format(jsonlog.RFC3339NanoFixed)),
   101  		},
   102  		// General, with both times Nano is preferred
   103  		JSONMessage{
   104  			Time:     now.Unix(),
   105  			TimeNano: now.UnixNano(),
   106  			ID:       "ID",
   107  			From:     "From",
   108  			Status:   "status",
   109  		}: {
   110  			fmt.Sprintf("%v ID: (from From) status\n", time.Unix(0, now.UnixNano()).Format(jsonlog.RFC3339NanoFixed)),
   111  			fmt.Sprintf("%v ID: (from From) status\n", time.Unix(0, now.UnixNano()).Format(jsonlog.RFC3339NanoFixed)),
   112  		},
   113  		// Stream over status
   114  		JSONMessage{
   115  			Status: "status",
   116  			Stream: "stream",
   117  		}: {
   118  			"stream",
   119  			"stream",
   120  		},
   121  		// With progress message
   122  		JSONMessage{
   123  			Status:          "status",
   124  			ProgressMessage: "progressMessage",
   125  		}: {
   126  			"status progressMessage",
   127  			"status progressMessage",
   128  		},
   129  		// With progress, stream empty
   130  		JSONMessage{
   131  			Status:   "status",
   132  			Stream:   "",
   133  			Progress: &JSONProgress{Current: 1},
   134  		}: {
   135  			"",
   136  			fmt.Sprintf("%c[1K%c[K\rstatus       1B\r", 27, 27),
   137  		},
   138  	}
   139  
   140  	// The tests :)
   141  	for jsonMessage, expectedMessages := range messages {
   142  		// Without terminal
   143  		data := bytes.NewBuffer([]byte{})
   144  		if err := jsonMessage.Display(data, nil); err != nil {
   145  			t.Fatal(err)
   146  		}
   147  		if data.String() != expectedMessages[0] {
   148  			t.Fatalf("Expected %q,got %q", expectedMessages[0], data.String())
   149  		}
   150  		// With terminal
   151  		data = bytes.NewBuffer([]byte{})
   152  		if err := jsonMessage.Display(data, &noTermInfo{}); err != nil {
   153  			t.Fatal(err)
   154  		}
   155  		if data.String() != expectedMessages[1] {
   156  			t.Fatalf("\nExpected %q\n     got %q", expectedMessages[1], data.String())
   157  		}
   158  	}
   159  }
   160  
   161  // Test JSONMessage with an Error. It will return an error with the text as error, not the meaning of the HTTP code.
   162  func TestJSONMessageDisplayWithJSONError(t *testing.T) {
   163  	data := bytes.NewBuffer([]byte{})
   164  	jsonMessage := JSONMessage{Error: &JSONError{404, "Can't find it"}}
   165  
   166  	err := jsonMessage.Display(data, &noTermInfo{})
   167  	if err == nil || err.Error() != "Can't find it" {
   168  		t.Fatalf("Expected a JSONError 404, got %q", err)
   169  	}
   170  
   171  	jsonMessage = JSONMessage{Error: &JSONError{401, "Anything"}}
   172  	err = jsonMessage.Display(data, &noTermInfo{})
   173  	if err == nil || err.Error() != "Authentication is required." {
   174  		t.Fatalf("Expected an error \"Authentication is required.\", got %q", err)
   175  	}
   176  }
   177  
   178  func TestDisplayJSONMessagesStreamInvalidJSON(t *testing.T) {
   179  	var (
   180  		inFd uintptr
   181  	)
   182  	data := bytes.NewBuffer([]byte{})
   183  	reader := strings.NewReader("This is not a 'valid' JSON []")
   184  	inFd, _ = term.GetFdInfo(reader)
   185  
   186  	if err := DisplayJSONMessagesStream(reader, data, inFd, false, nil); err == nil && err.Error()[:17] != "invalid character" {
   187  		t.Fatalf("Should have thrown an error (invalid character in ..), got %q", err)
   188  	}
   189  }
   190  
   191  func TestDisplayJSONMessagesStream(t *testing.T) {
   192  	var (
   193  		inFd uintptr
   194  	)
   195  
   196  	messages := map[string][]string{
   197  		// empty string
   198  		"": {
   199  			"",
   200  			""},
   201  		// Without progress & ID
   202  		"{ \"status\": \"status\" }": {
   203  			"status\n",
   204  			"status\n",
   205  		},
   206  		// Without progress, with ID
   207  		"{ \"id\": \"ID\",\"status\": \"status\" }": {
   208  			"ID: status\n",
   209  			fmt.Sprintf("ID: status\n"),
   210  		},
   211  		// With progress
   212  		"{ \"id\": \"ID\", \"status\": \"status\", \"progress\": \"ProgressMessage\" }": {
   213  			"ID: status ProgressMessage",
   214  			fmt.Sprintf("\n%c[%dAID: status ProgressMessage%c[%dB", 27, 1, 27, 1),
   215  		},
   216  		// With progressDetail
   217  		"{ \"id\": \"ID\", \"status\": \"status\", \"progressDetail\": { \"Current\": 1} }": {
   218  			"", // progressbar is disabled in non-terminal
   219  			fmt.Sprintf("\n%c[%dA%c[1K%c[K\rID: status       1B\r%c[%dB", 27, 1, 27, 27, 27, 1),
   220  		},
   221  	}
   222  
   223  	// Use $TERM which is unlikely to exist, forcing DisplayJSONMessageStream to
   224  	// (hopefully) use &noTermInfo.
   225  	origTerm := os.Getenv("TERM")
   226  	os.Setenv("TERM", "xyzzy-non-existent-terminfo")
   227  
   228  	for jsonMessage, expectedMessages := range messages {
   229  		data := bytes.NewBuffer([]byte{})
   230  		reader := strings.NewReader(jsonMessage)
   231  		inFd, _ = term.GetFdInfo(reader)
   232  
   233  		// Without terminal
   234  		if err := DisplayJSONMessagesStream(reader, data, inFd, false, nil); err != nil {
   235  			t.Fatal(err)
   236  		}
   237  		if data.String() != expectedMessages[0] {
   238  			t.Fatalf("Expected an %q, got %q", expectedMessages[0], data.String())
   239  		}
   240  
   241  		// With terminal
   242  		data = bytes.NewBuffer([]byte{})
   243  		reader = strings.NewReader(jsonMessage)
   244  		if err := DisplayJSONMessagesStream(reader, data, inFd, true, nil); err != nil {
   245  			t.Fatal(err)
   246  		}
   247  		if data.String() != expectedMessages[1] {
   248  			t.Fatalf("\nExpected %q\n     got %q", expectedMessages[1], data.String())
   249  		}
   250  	}
   251  	os.Setenv("TERM", origTerm)
   252  
   253  }