container_copy_test.go 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. package client // import "github.com/docker/docker/client"
  2. import (
  3. "bytes"
  4. "context"
  5. "encoding/base64"
  6. "encoding/json"
  7. "fmt"
  8. "io"
  9. "net/http"
  10. "strings"
  11. "testing"
  12. "github.com/docker/docker/api/types"
  13. "github.com/docker/docker/errdefs"
  14. )
  15. func TestContainerStatPathError(t *testing.T) {
  16. client := &Client{
  17. client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
  18. }
  19. _, err := client.ContainerStatPath(context.Background(), "container_id", "path")
  20. if !errdefs.IsSystem(err) {
  21. t.Fatalf("expected a Server Error, got %[1]T: %[1]v", err)
  22. }
  23. }
  24. func TestContainerStatPathNotFoundError(t *testing.T) {
  25. client := &Client{
  26. client: newMockClient(errorMock(http.StatusNotFound, "Not found")),
  27. }
  28. _, err := client.ContainerStatPath(context.Background(), "container_id", "path")
  29. if !IsErrNotFound(err) {
  30. t.Fatalf("expected a not found error, got %v", err)
  31. }
  32. }
  33. func TestContainerStatPathNoHeaderError(t *testing.T) {
  34. client := &Client{
  35. client: newMockClient(func(req *http.Request) (*http.Response, error) {
  36. return &http.Response{
  37. StatusCode: http.StatusOK,
  38. Body: io.NopCloser(bytes.NewReader([]byte(""))),
  39. }, nil
  40. }),
  41. }
  42. _, err := client.ContainerStatPath(context.Background(), "container_id", "path/to/file")
  43. if err == nil {
  44. t.Fatalf("expected an error, got nothing")
  45. }
  46. }
  47. func TestContainerStatPath(t *testing.T) {
  48. expectedURL := "/containers/container_id/archive"
  49. expectedPath := "path/to/file"
  50. client := &Client{
  51. client: newMockClient(func(req *http.Request) (*http.Response, error) {
  52. if !strings.HasPrefix(req.URL.Path, expectedURL) {
  53. return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL)
  54. }
  55. if req.Method != http.MethodHead {
  56. return nil, fmt.Errorf("expected HEAD method, got %s", req.Method)
  57. }
  58. query := req.URL.Query()
  59. path := query.Get("path")
  60. if path != expectedPath {
  61. return nil, fmt.Errorf("path not set in URL query properly")
  62. }
  63. content, err := json.Marshal(types.ContainerPathStat{
  64. Name: "name",
  65. Mode: 0700,
  66. })
  67. if err != nil {
  68. return nil, err
  69. }
  70. base64PathStat := base64.StdEncoding.EncodeToString(content)
  71. return &http.Response{
  72. StatusCode: http.StatusOK,
  73. Body: io.NopCloser(bytes.NewReader([]byte(""))),
  74. Header: http.Header{
  75. "X-Docker-Container-Path-Stat": []string{base64PathStat},
  76. },
  77. }, nil
  78. }),
  79. }
  80. stat, err := client.ContainerStatPath(context.Background(), "container_id", expectedPath)
  81. if err != nil {
  82. t.Fatal(err)
  83. }
  84. if stat.Name != "name" {
  85. t.Fatalf("expected container path stat name to be 'name', got '%s'", stat.Name)
  86. }
  87. if stat.Mode != 0700 {
  88. t.Fatalf("expected container path stat mode to be 0700, got '%v'", stat.Mode)
  89. }
  90. }
  91. func TestCopyToContainerError(t *testing.T) {
  92. client := &Client{
  93. client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
  94. }
  95. err := client.CopyToContainer(context.Background(), "container_id", "path/to/file", bytes.NewReader([]byte("")), types.CopyToContainerOptions{})
  96. if !errdefs.IsSystem(err) {
  97. t.Fatalf("expected a Server Error, got %[1]T: %[1]v", err)
  98. }
  99. }
  100. func TestCopyToContainerNotFoundError(t *testing.T) {
  101. client := &Client{
  102. client: newMockClient(errorMock(http.StatusNotFound, "Not found")),
  103. }
  104. err := client.CopyToContainer(context.Background(), "container_id", "path/to/file", bytes.NewReader([]byte("")), types.CopyToContainerOptions{})
  105. if !IsErrNotFound(err) {
  106. t.Fatalf("expected a not found error, got %v", err)
  107. }
  108. }
  109. // TODO TestCopyToContainerNotStatusOKError expects a non-error status-code ("204 No Content") to produce an error; verify if this is the desired behavior
  110. func TestCopyToContainerNotStatusOKError(t *testing.T) {
  111. client := &Client{
  112. client: newMockClient(errorMock(http.StatusNoContent, "No content")),
  113. }
  114. err := client.CopyToContainer(context.Background(), "container_id", "path/to/file", bytes.NewReader([]byte("")), types.CopyToContainerOptions{})
  115. if err == nil || err.Error() != "unexpected status code from daemon: 204" {
  116. t.Fatalf("expected an unexpected status code error, got %v", err)
  117. }
  118. }
  119. func TestCopyToContainer(t *testing.T) {
  120. expectedURL := "/containers/container_id/archive"
  121. expectedPath := "path/to/file"
  122. client := &Client{
  123. client: newMockClient(func(req *http.Request) (*http.Response, error) {
  124. if !strings.HasPrefix(req.URL.Path, expectedURL) {
  125. return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL)
  126. }
  127. if req.Method != http.MethodPut {
  128. return nil, fmt.Errorf("expected PUT method, got %s", req.Method)
  129. }
  130. query := req.URL.Query()
  131. path := query.Get("path")
  132. if path != expectedPath {
  133. return nil, fmt.Errorf("path not set in URL query properly, expected '%s', got %s", expectedPath, path)
  134. }
  135. noOverwriteDirNonDir := query.Get("noOverwriteDirNonDir")
  136. if noOverwriteDirNonDir != "true" {
  137. return nil, fmt.Errorf("noOverwriteDirNonDir not set in URL query properly, expected true, got %s", noOverwriteDirNonDir)
  138. }
  139. content, err := io.ReadAll(req.Body)
  140. if err != nil {
  141. return nil, err
  142. }
  143. if err := req.Body.Close(); err != nil {
  144. return nil, err
  145. }
  146. if string(content) != "content" {
  147. return nil, fmt.Errorf("expected content to be 'content', got %s", string(content))
  148. }
  149. return &http.Response{
  150. StatusCode: http.StatusOK,
  151. Body: io.NopCloser(bytes.NewReader([]byte(""))),
  152. }, nil
  153. }),
  154. }
  155. err := client.CopyToContainer(context.Background(), "container_id", expectedPath, bytes.NewReader([]byte("content")), types.CopyToContainerOptions{
  156. AllowOverwriteDirWithFile: false,
  157. })
  158. if err != nil {
  159. t.Fatal(err)
  160. }
  161. }
  162. func TestCopyFromContainerError(t *testing.T) {
  163. client := &Client{
  164. client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
  165. }
  166. _, _, err := client.CopyFromContainer(context.Background(), "container_id", "path/to/file")
  167. if !errdefs.IsSystem(err) {
  168. t.Fatalf("expected a Server Error, got %[1]T: %[1]v", err)
  169. }
  170. }
  171. func TestCopyFromContainerNotFoundError(t *testing.T) {
  172. client := &Client{
  173. client: newMockClient(errorMock(http.StatusNotFound, "Not found")),
  174. }
  175. _, _, err := client.CopyFromContainer(context.Background(), "container_id", "path/to/file")
  176. if !IsErrNotFound(err) {
  177. t.Fatalf("expected a not found error, got %v", err)
  178. }
  179. }
  180. // TODO TestCopyFromContainerNotStatusOKError expects a non-error status-code ("204 No Content") to produce an error; verify if this is the desired behavior
  181. func TestCopyFromContainerNotStatusOKError(t *testing.T) {
  182. client := &Client{
  183. client: newMockClient(errorMock(http.StatusNoContent, "No content")),
  184. }
  185. _, _, err := client.CopyFromContainer(context.Background(), "container_id", "path/to/file")
  186. if err == nil || err.Error() != "unexpected status code from daemon: 204" {
  187. t.Fatalf("expected an unexpected status code error, got %v", err)
  188. }
  189. }
  190. func TestCopyFromContainerNoHeaderError(t *testing.T) {
  191. client := &Client{
  192. client: newMockClient(func(req *http.Request) (*http.Response, error) {
  193. return &http.Response{
  194. StatusCode: http.StatusOK,
  195. Body: io.NopCloser(bytes.NewReader([]byte(""))),
  196. }, nil
  197. }),
  198. }
  199. _, _, err := client.CopyFromContainer(context.Background(), "container_id", "path/to/file")
  200. if err == nil {
  201. t.Fatalf("expected an error, got nothing")
  202. }
  203. }
  204. func TestCopyFromContainer(t *testing.T) {
  205. expectedURL := "/containers/container_id/archive"
  206. expectedPath := "path/to/file"
  207. client := &Client{
  208. client: newMockClient(func(req *http.Request) (*http.Response, error) {
  209. if !strings.HasPrefix(req.URL.Path, expectedURL) {
  210. return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL)
  211. }
  212. if req.Method != http.MethodGet {
  213. return nil, fmt.Errorf("expected GET method, got %s", req.Method)
  214. }
  215. query := req.URL.Query()
  216. path := query.Get("path")
  217. if path != expectedPath {
  218. return nil, fmt.Errorf("path not set in URL query properly, expected '%s', got %s", expectedPath, path)
  219. }
  220. headercontent, err := json.Marshal(types.ContainerPathStat{
  221. Name: "name",
  222. Mode: 0700,
  223. })
  224. if err != nil {
  225. return nil, err
  226. }
  227. base64PathStat := base64.StdEncoding.EncodeToString(headercontent)
  228. return &http.Response{
  229. StatusCode: http.StatusOK,
  230. Body: io.NopCloser(bytes.NewReader([]byte("content"))),
  231. Header: http.Header{
  232. "X-Docker-Container-Path-Stat": []string{base64PathStat},
  233. },
  234. }, nil
  235. }),
  236. }
  237. r, stat, err := client.CopyFromContainer(context.Background(), "container_id", expectedPath)
  238. if err != nil {
  239. t.Fatal(err)
  240. }
  241. if stat.Name != "name" {
  242. t.Fatalf("expected container path stat name to be 'name', got '%s'", stat.Name)
  243. }
  244. if stat.Mode != 0700 {
  245. t.Fatalf("expected container path stat mode to be 0700, got '%v'", stat.Mode)
  246. }
  247. content, err := io.ReadAll(r)
  248. if err != nil {
  249. t.Fatal(err)
  250. }
  251. if err := r.Close(); err != nil {
  252. t.Fatal(err)
  253. }
  254. if string(content) != "content" {
  255. t.Fatalf("expected content to be 'content', got %s", string(content))
  256. }
  257. }