1
0

swift_test.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. package swift
  2. import (
  3. "context"
  4. "net/http"
  5. "testing"
  6. "time"
  7. "github.com/ncw/swift/v2"
  8. "github.com/ncw/swift/v2/swifttest"
  9. "github.com/stretchr/testify/suite"
  10. "github.com/imgproxy/imgproxy/v3/fetcher/transport/generichttp"
  11. )
  12. const (
  13. testContainer = "test"
  14. testObject = "foo/test.png"
  15. )
  16. type SwiftTestSuite struct {
  17. suite.Suite
  18. server *swifttest.SwiftServer
  19. transport http.RoundTripper
  20. etag string
  21. lastModified time.Time
  22. }
  23. func (s *SwiftTestSuite) SetupSuite() {
  24. s.server, _ = swifttest.NewSwiftServer("localhost")
  25. config := NewDefaultConfig()
  26. config.AuthURL = s.server.AuthURL
  27. config.Username = swifttest.TEST_ACCOUNT
  28. config.APIKey = swifttest.TEST_ACCOUNT
  29. config.AuthVersion = 1
  30. s.setupTestFile(&config)
  31. tc := generichttp.NewDefaultConfig()
  32. tc.IgnoreSslVerification = true
  33. trans, gerr := generichttp.New(false, &tc)
  34. s.Require().NoError(gerr)
  35. var err error
  36. s.transport, err = New(&config, trans)
  37. s.Require().NoError(err, "failed to initialize swift transport")
  38. }
  39. func (s *SwiftTestSuite) setupTestFile(config *Config) {
  40. c := &swift.Connection{
  41. UserName: config.Username,
  42. ApiKey: config.APIKey,
  43. AuthUrl: config.AuthURL,
  44. AuthVersion: config.AuthVersion,
  45. }
  46. ctx := context.Background()
  47. err := c.Authenticate(ctx)
  48. s.Require().NoError(err, "failed to authenticate with test server")
  49. err = c.ContainerCreate(ctx, testContainer, nil)
  50. s.Require().NoError(err, "failed to create container")
  51. f, err := c.ObjectCreate(ctx, testContainer, testObject, true, "", "image/png", nil)
  52. s.Require().NoError(err, "failed to create object")
  53. defer f.Close()
  54. data := make([]byte, 32)
  55. n, err := f.Write(data)
  56. s.Require().Len(data, n)
  57. s.Require().NoError(err)
  58. f.Close()
  59. // The Etag is written on file close; but Last-Modified is only available when we get the object again.
  60. _, h, err := c.Object(ctx, testContainer, testObject)
  61. s.Require().NoError(err)
  62. s.etag = h["Etag"]
  63. s.lastModified, err = time.Parse(http.TimeFormat, h["Date"])
  64. s.Require().NoError(err)
  65. }
  66. func (s *SwiftTestSuite) TearDownSuite() {
  67. s.server.Close()
  68. }
  69. func (s *SwiftTestSuite) TestRoundTripReturns404WhenObjectNotFound() {
  70. request, _ := http.NewRequest("GET", "swift://test/foo/not-here.png", nil)
  71. response, err := s.transport.RoundTrip(request)
  72. s.Require().NoError(err)
  73. s.Require().Equal(404, response.StatusCode)
  74. }
  75. func (s *SwiftTestSuite) TestRoundTripReturns404WhenContainerNotFound() {
  76. request, _ := http.NewRequest("GET", "swift://invalid/foo/test.png", nil)
  77. response, err := s.transport.RoundTrip(request)
  78. s.Require().NoError(err)
  79. s.Require().Equal(404, response.StatusCode)
  80. }
  81. func (s *SwiftTestSuite) TestRoundTripWithETagEnabled() {
  82. request, _ := http.NewRequest("GET", "swift://test/foo/test.png", nil)
  83. response, err := s.transport.RoundTrip(request)
  84. s.Require().NoError(err)
  85. s.Require().Equal(200, response.StatusCode)
  86. s.Require().Equal(s.etag, response.Header.Get("ETag"))
  87. }
  88. func (s *SwiftTestSuite) TestRoundTripWithIfNoneMatchReturns304() {
  89. request, _ := http.NewRequest("GET", "swift://test/foo/test.png", nil)
  90. request.Header.Set("If-None-Match", s.etag)
  91. response, err := s.transport.RoundTrip(request)
  92. s.Require().NoError(err)
  93. s.Require().Equal(http.StatusNotModified, response.StatusCode)
  94. }
  95. func (s *SwiftTestSuite) TestRoundTripWithUpdatedETagReturns200() {
  96. request, _ := http.NewRequest("GET", "swift://test/foo/test.png", nil)
  97. request.Header.Set("If-None-Match", s.etag+"_wrong")
  98. response, err := s.transport.RoundTrip(request)
  99. s.Require().NoError(err)
  100. s.Require().Equal(http.StatusOK, response.StatusCode)
  101. }
  102. func (s *SwiftTestSuite) TestRoundTripWithLastModifiedEnabled() {
  103. request, _ := http.NewRequest("GET", "swift://test/foo/test.png", nil)
  104. response, err := s.transport.RoundTrip(request)
  105. s.Require().NoError(err)
  106. s.Require().Equal(200, response.StatusCode)
  107. s.Require().Equal(s.lastModified.Format(http.TimeFormat), response.Header.Get("Last-Modified"))
  108. }
  109. func (s *SwiftTestSuite) TestRoundTripWithIfModifiedSinceReturns304() {
  110. request, _ := http.NewRequest("GET", "swift://test/foo/test.png", nil)
  111. request.Header.Set("If-Modified-Since", s.lastModified.Format(http.TimeFormat))
  112. response, err := s.transport.RoundTrip(request)
  113. s.Require().NoError(err)
  114. s.Require().Equal(http.StatusNotModified, response.StatusCode)
  115. }
  116. func (s *SwiftTestSuite) TestRoundTripWithUpdatedLastModifiedReturns200() {
  117. request, _ := http.NewRequest("GET", "swift://test/foo/test.png", nil)
  118. request.Header.Set("If-Modified-Since", s.lastModified.Add(-24*time.Hour).Format(http.TimeFormat))
  119. response, err := s.transport.RoundTrip(request)
  120. s.Require().NoError(err)
  121. s.Require().Equal(http.StatusOK, response.StatusCode)
  122. }
  123. func TestSwiftTransport(t *testing.T) {
  124. suite.Run(t, new(SwiftTestSuite))
  125. }