github.com/vnpaycloud-console/gophercloud/v2@v2.0.5/openstack/objectstorage/v1/objects/testing/fixtures_test.go (about)

     1  package testing
     2  
     3  import (
     4  	"crypto/md5"
     5  	"fmt"
     6  	"io"
     7  	"net/http"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/vnpaycloud-console/gophercloud/v2/openstack/objectstorage/v1/objects"
    12  	th "github.com/vnpaycloud-console/gophercloud/v2/testhelper"
    13  	fake "github.com/vnpaycloud-console/gophercloud/v2/testhelper/client"
    14  )
    15  
    16  type handlerOptions struct {
    17  	path string
    18  }
    19  
    20  type option func(*handlerOptions)
    21  
    22  func WithPath(s string) option {
    23  	return func(h *handlerOptions) {
    24  		h.path = s
    25  	}
    26  }
    27  
    28  // HandleDownloadObjectSuccessfully creates an HTTP handler at `/testContainer/testObject` on the test handler mux that
    29  // responds with a `Download` response.
    30  func HandleDownloadObjectSuccessfully(t *testing.T, options ...option) {
    31  	ho := handlerOptions{
    32  		path: "/testContainer/testObject",
    33  	}
    34  	for _, apply := range options {
    35  		apply(&ho)
    36  	}
    37  
    38  	th.Mux.HandleFunc(ho.path, func(w http.ResponseWriter, r *http.Request) {
    39  		date := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
    40  		th.TestMethod(t, r, "GET")
    41  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
    42  		th.TestHeader(t, r, "Accept", "application/json")
    43  		w.Header().Set("Date", date.Format(time.RFC1123))
    44  		w.Header().Set("X-Static-Large-Object", "True")
    45  
    46  		unModifiedSince := r.Header.Get("If-Unmodified-Since")
    47  		modifiedSince := r.Header.Get("If-Modified-Since")
    48  		if unModifiedSince != "" {
    49  			ums, _ := time.Parse(time.RFC1123, unModifiedSince)
    50  			if ums.Before(date) || ums.Equal(date) {
    51  				w.WriteHeader(http.StatusPreconditionFailed)
    52  				return
    53  			}
    54  		}
    55  		if modifiedSince != "" {
    56  			ms, _ := time.Parse(time.RFC1123, modifiedSince)
    57  			if ms.After(date) {
    58  				w.WriteHeader(http.StatusNotModified)
    59  				return
    60  			}
    61  		}
    62  		w.Header().Set("Last-Modified", date.Format(time.RFC1123))
    63  		w.WriteHeader(http.StatusOK)
    64  		fmt.Fprint(w, "Successful download with Gophercloud")
    65  	})
    66  }
    67  
    68  // ExpectedListInfo is the result expected from a call to `List` when full
    69  // info is requested.
    70  var ExpectedListInfo = []objects.Object{
    71  	{
    72  		Hash:         "451e372e48e0f6b1114fa0724aa79fa1",
    73  		LastModified: time.Date(2016, time.August, 17, 22, 11, 58, 602650000, time.UTC),
    74  		Bytes:        14,
    75  		Name:         "goodbye",
    76  		ContentType:  "application/octet-stream",
    77  	},
    78  	{
    79  		Hash:         "451e372e48e0f6b1114fa0724aa79fa1",
    80  		LastModified: time.Date(2016, time.August, 17, 22, 11, 58, 602650000, time.UTC),
    81  		Bytes:        14,
    82  		Name:         "hello",
    83  		ContentType:  "application/octet-stream",
    84  	},
    85  }
    86  
    87  // ExpectedListSubdir is the result expected from a call to `List` when full
    88  // info is requested.
    89  var ExpectedListSubdir = []objects.Object{
    90  	{
    91  		Subdir: "directory/",
    92  	},
    93  }
    94  
    95  // ExpectedListNames is the result expected from a call to `List` when just
    96  // object names are requested.
    97  var ExpectedListNames = []string{"goodbye", "hello"}
    98  
    99  // HandleListObjectsInfoSuccessfully creates an HTTP handler at `/testContainer` on the test handler mux that
   100  // responds with a `List` response when full info is requested.
   101  func HandleListObjectsInfoSuccessfully(t *testing.T, options ...option) {
   102  	ho := handlerOptions{
   103  		path: "/testContainer",
   104  	}
   105  	for _, apply := range options {
   106  		apply(&ho)
   107  	}
   108  
   109  	th.Mux.HandleFunc(ho.path, func(w http.ResponseWriter, r *http.Request) {
   110  		th.TestMethod(t, r, "GET")
   111  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   112  		th.TestHeader(t, r, "Accept", "application/json")
   113  
   114  		w.Header().Set("Content-Type", "application/json")
   115  		if err := r.ParseForm(); err != nil {
   116  			t.Errorf("Failed to parse request form %v", err)
   117  		}
   118  		marker := r.Form.Get("marker")
   119  		switch marker {
   120  		case "":
   121  			fmt.Fprint(w, `[
   122        {
   123          "hash": "451e372e48e0f6b1114fa0724aa79fa1",
   124          "last_modified": "2016-08-17T22:11:58.602650",
   125          "bytes": 14,
   126          "name": "goodbye",
   127          "content_type": "application/octet-stream"
   128        },
   129        {
   130          "hash": "451e372e48e0f6b1114fa0724aa79fa1",
   131          "last_modified": "2016-08-17T22:11:58.602650",
   132          "bytes": 14,
   133          "name": "hello",
   134          "content_type": "application/octet-stream"
   135        }
   136      ]`)
   137  		case "hello":
   138  			fmt.Fprint(w, `[]`)
   139  		default:
   140  			t.Fatalf("Unexpected marker: [%s]", marker)
   141  		}
   142  	})
   143  }
   144  
   145  // HandleListSubdirSuccessfully creates an HTTP handler at `/testContainer` on the test handler mux that
   146  // responds with a `List` response when full info is requested.
   147  func HandleListSubdirSuccessfully(t *testing.T) {
   148  	th.Mux.HandleFunc("/testContainer", func(w http.ResponseWriter, r *http.Request) {
   149  		th.TestMethod(t, r, "GET")
   150  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   151  		th.TestHeader(t, r, "Accept", "application/json")
   152  
   153  		w.Header().Set("Content-Type", "application/json")
   154  		if err := r.ParseForm(); err != nil {
   155  			t.Errorf("Failed to parse request form %v", err)
   156  		}
   157  		marker := r.Form.Get("marker")
   158  		switch marker {
   159  		case "":
   160  			fmt.Fprint(w, `[
   161        {
   162          "subdir": "directory/"
   163        }
   164      ]`)
   165  		case "directory/":
   166  			fmt.Fprint(w, `[]`)
   167  		default:
   168  			t.Fatalf("Unexpected marker: [%s]", marker)
   169  		}
   170  	})
   171  }
   172  
   173  // HandleListZeroObjectNames204 creates an HTTP handler at `/testContainer` on the test handler mux that
   174  // responds with "204 No Content" when object names are requested. This happens on some, but not all, objectstorage
   175  // instances. This case is peculiar in that the server sends no `content-type` header.
   176  func HandleListZeroObjectNames204(t *testing.T) {
   177  	th.Mux.HandleFunc("/testContainer", func(w http.ResponseWriter, r *http.Request) {
   178  		th.TestMethod(t, r, "GET")
   179  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   180  		th.TestHeader(t, r, "Accept", "application/json")
   181  
   182  		w.WriteHeader(http.StatusNoContent)
   183  	})
   184  }
   185  
   186  // HandleCreateTextObjectSuccessfully creates an HTTP handler at `/testContainer/testObject` on the test handler mux
   187  // that responds with a `Create` response. A Content-Type of "text/plain" is expected.
   188  func HandleCreateTextObjectSuccessfully(t *testing.T, content string, options ...option) {
   189  	ho := handlerOptions{
   190  		path: "/testContainer/testObject",
   191  	}
   192  	for _, apply := range options {
   193  		apply(&ho)
   194  	}
   195  
   196  	th.Mux.HandleFunc(ho.path, func(w http.ResponseWriter, r *http.Request) {
   197  		th.TestMethod(t, r, "PUT")
   198  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   199  		th.TestHeader(t, r, "Content-Type", "text/plain")
   200  		th.TestHeader(t, r, "Accept", "application/json")
   201  		th.TestBody(t, r, `Did gyre and gimble in the wabe`)
   202  
   203  		hash := md5.New()
   204  		_, err := io.WriteString(hash, content)
   205  		th.AssertNoErr(t, err)
   206  		localChecksum := hash.Sum(nil)
   207  
   208  		w.Header().Set("ETag", fmt.Sprintf("%x", localChecksum))
   209  		w.WriteHeader(http.StatusCreated)
   210  	})
   211  }
   212  
   213  // HandleCreateTextWithCacheControlSuccessfully creates an HTTP handler at `/testContainer/testObject` on the test handler
   214  // mux that responds with a `Create` response. A Cache-Control of `max-age="3600", public` is expected.
   215  func HandleCreateTextWithCacheControlSuccessfully(t *testing.T, content string) {
   216  	th.Mux.HandleFunc("/testContainer/testObject", func(w http.ResponseWriter, r *http.Request) {
   217  		th.TestMethod(t, r, "PUT")
   218  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   219  		th.TestHeader(t, r, "Cache-Control", `max-age="3600", public`)
   220  		th.TestHeader(t, r, "Accept", "application/json")
   221  		th.TestBody(t, r, `All mimsy were the borogoves`)
   222  
   223  		hash := md5.New()
   224  		_, err := io.WriteString(hash, content)
   225  		th.AssertNoErr(t, err)
   226  		localChecksum := hash.Sum(nil)
   227  
   228  		w.Header().Set("ETag", fmt.Sprintf("%x", localChecksum))
   229  		w.WriteHeader(http.StatusCreated)
   230  	})
   231  }
   232  
   233  // HandleCreateTypelessObjectSuccessfully creates an HTTP handler at `/testContainer/testObject` on the test handler
   234  // mux that responds with a `Create` response. No Content-Type header may be present in the request, so that server-
   235  // side content-type detection will be triggered properly.
   236  func HandleCreateTypelessObjectSuccessfully(t *testing.T, content string) {
   237  	th.Mux.HandleFunc("/testContainer/testObject", func(w http.ResponseWriter, r *http.Request) {
   238  		th.TestMethod(t, r, "PUT")
   239  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   240  		th.TestHeader(t, r, "Accept", "application/json")
   241  		th.TestBody(t, r, `The sky was the color of television, tuned to a dead channel.`)
   242  
   243  		if contentType, present := r.Header["Content-Type"]; present {
   244  			t.Errorf("Expected Content-Type header to be omitted, but was %#v", contentType)
   245  		}
   246  
   247  		hash := md5.New()
   248  		_, err := io.WriteString(hash, content)
   249  		th.AssertNoErr(t, err)
   250  		localChecksum := hash.Sum(nil)
   251  
   252  		w.Header().Set("ETag", fmt.Sprintf("%x", localChecksum))
   253  		w.WriteHeader(http.StatusCreated)
   254  	})
   255  }
   256  
   257  // HandleCopyObjectSuccessfully creates an HTTP handler at `/testContainer/testObject` on the test handler mux that
   258  // responds with a `Copy` response.
   259  func HandleCopyObjectSuccessfully(t *testing.T, destination string) {
   260  	th.Mux.HandleFunc("/testContainer/testObject", func(w http.ResponseWriter, r *http.Request) {
   261  		th.TestMethod(t, r, "COPY")
   262  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   263  		th.TestHeader(t, r, "Accept", "application/json")
   264  		th.TestHeader(t, r, "Destination", destination)
   265  		w.WriteHeader(http.StatusCreated)
   266  	})
   267  }
   268  
   269  // HandleCopyObjectSuccessfully creates an HTTP handler at `/testContainer/testObject` on the test handler mux that
   270  // responds with a `Copy` response.
   271  func HandleCopyObjectVersionSuccessfully(t *testing.T) {
   272  	th.Mux.HandleFunc("/testContainer/testObject", func(w http.ResponseWriter, r *http.Request) {
   273  		th.TestMethod(t, r, "COPY")
   274  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   275  		th.TestHeader(t, r, "Accept", "application/json")
   276  		th.TestHeader(t, r, "Destination", "/newTestContainer/newTestObject")
   277  		th.TestFormValues(t, r, map[string]string{"version-id": "123456788"})
   278  		w.Header().Set("X-Object-Version-Id", "123456789")
   279  		w.WriteHeader(http.StatusCreated)
   280  	})
   281  }
   282  
   283  // HandleDeleteObjectSuccessfully creates an HTTP handler at `/testContainer/testObject` on the test handler mux that
   284  // responds with a `Delete` response.
   285  func HandleDeleteObjectSuccessfully(t *testing.T, options ...option) {
   286  	ho := handlerOptions{
   287  		path: "/testContainer/testObject",
   288  	}
   289  	for _, apply := range options {
   290  		apply(&ho)
   291  	}
   292  
   293  	th.Mux.HandleFunc(ho.path, func(w http.ResponseWriter, r *http.Request) {
   294  		th.TestMethod(t, r, "DELETE")
   295  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   296  		th.TestHeader(t, r, "Accept", "application/json")
   297  		w.WriteHeader(http.StatusNoContent)
   298  	})
   299  }
   300  
   301  const bulkDeleteResponse = `
   302  {
   303      "Response Status": "foo",
   304      "Response Body": "bar",
   305      "Errors": [],
   306      "Number Deleted": 2,
   307      "Number Not Found": 0
   308  }
   309  `
   310  
   311  // HandleBulkDeleteSuccessfully creates an HTTP handler at `/` on the test
   312  // handler mux that responds with a `BulkDelete` response.
   313  func HandleBulkDeleteSuccessfully(t *testing.T) {
   314  	th.Mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
   315  		th.TestMethod(t, r, "POST")
   316  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   317  		th.TestHeader(t, r, "Accept", "application/json")
   318  		th.TestHeader(t, r, "Content-Type", "text/plain")
   319  		th.TestFormValues(t, r, map[string]string{
   320  			"bulk-delete": "true",
   321  		})
   322  		th.TestBody(t, r, "testContainer/testObject1\ntestContainer/testObject2\n")
   323  
   324  		w.Header().Set("Content-Type", "application/json")
   325  		w.WriteHeader(http.StatusOK)
   326  		fmt.Fprint(w, bulkDeleteResponse)
   327  	})
   328  }
   329  
   330  // HandleUpdateObjectSuccessfully creates an HTTP handler at `/testContainer/testObject` on the test handler mux that
   331  // responds with a `Update` response.
   332  func HandleUpdateObjectSuccessfully(t *testing.T, options ...option) {
   333  	ho := handlerOptions{
   334  		path: "/testContainer/testObject",
   335  	}
   336  	for _, apply := range options {
   337  		apply(&ho)
   338  	}
   339  
   340  	th.Mux.HandleFunc(ho.path, func(w http.ResponseWriter, r *http.Request) {
   341  		th.TestMethod(t, r, "POST")
   342  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   343  		th.TestHeader(t, r, "Accept", "application/json")
   344  		th.TestHeader(t, r, "X-Object-Meta-Gophercloud-Test", "objects")
   345  		th.TestHeader(t, r, "X-Remove-Object-Meta-Gophercloud-Test-Remove", "remove")
   346  		th.TestHeader(t, r, "Content-Disposition", "")
   347  		th.TestHeader(t, r, "Content-Encoding", "")
   348  		th.TestHeader(t, r, "Content-Type", "")
   349  		th.TestHeaderUnset(t, r, "X-Delete-After")
   350  		th.TestHeader(t, r, "X-Delete-At", "0")
   351  		th.TestHeader(t, r, "X-Detect-Content-Type", "false")
   352  		w.WriteHeader(http.StatusAccepted)
   353  	})
   354  }
   355  
   356  // HandleGetObjectSuccessfully creates an HTTP handler at `/testContainer/testObject` on the test handler mux that
   357  // responds with a `Get` response.
   358  func HandleGetObjectSuccessfully(t *testing.T, options ...option) {
   359  	ho := handlerOptions{
   360  		path: "/testContainer/testObject",
   361  	}
   362  	for _, apply := range options {
   363  		apply(&ho)
   364  	}
   365  
   366  	th.Mux.HandleFunc(ho.path, func(w http.ResponseWriter, r *http.Request) {
   367  		th.TestMethod(t, r, "HEAD")
   368  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   369  		th.TestHeader(t, r, "Accept", "application/json")
   370  		w.Header().Add("X-Object-Meta-Gophercloud-Test", "objects")
   371  		w.Header().Add("X-Static-Large-Object", "true")
   372  		w.WriteHeader(http.StatusNoContent)
   373  	})
   374  }