jsonmessage_test.go 7.1 KB

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