github.com/leeclow-ops/gophercloud@v1.2.1/acceptance/openstack/objectstorage/v1/objects_test.go (about)

     1  //go:build acceptance
     2  // +build acceptance
     3  
     4  package v1
     5  
     6  import (
     7  	"bytes"
     8  	"io/ioutil"
     9  	"net/http"
    10  	"strings"
    11  	"testing"
    12  
    13  	"github.com/leeclow-ops/gophercloud/acceptance/clients"
    14  	"github.com/leeclow-ops/gophercloud/acceptance/tools"
    15  	"github.com/leeclow-ops/gophercloud/openstack/objectstorage/v1/containers"
    16  	"github.com/leeclow-ops/gophercloud/openstack/objectstorage/v1/objects"
    17  	th "github.com/leeclow-ops/gophercloud/testhelper"
    18  )
    19  
    20  // numObjects is the number of objects to create for testing.
    21  var numObjects = 2
    22  
    23  func TestObjects(t *testing.T) {
    24  	client, err := clients.NewObjectStorageV1Client()
    25  	if err != nil {
    26  		t.Fatalf("Unable to create client: %v", err)
    27  	}
    28  
    29  	// Make a slice of length numObjects to hold the random object names.
    30  	oNames := make([]string, numObjects)
    31  	for i := 0; i < len(oNames); i++ {
    32  		oNames[i] = tools.RandomString("test-object-", 8)
    33  	}
    34  
    35  	// Create a container to hold the test objects.
    36  	cName := tools.RandomString("test-container-", 8)
    37  	header, err := containers.Create(client, cName, nil).Extract()
    38  	th.AssertNoErr(t, err)
    39  	t.Logf("Create object headers: %+v\n", header)
    40  
    41  	// Defer deletion of the container until after testing.
    42  	defer func() {
    43  		res := containers.Delete(client, cName)
    44  		th.AssertNoErr(t, res.Err)
    45  	}()
    46  
    47  	// Create a slice of buffers to hold the test object content.
    48  	oContents := make([]*bytes.Buffer, numObjects)
    49  	for i := 0; i < numObjects; i++ {
    50  		oContents[i] = bytes.NewBuffer([]byte(tools.RandomString("", 10)))
    51  		createOpts := objects.CreateOpts{
    52  			Content: oContents[i],
    53  		}
    54  		res := objects.Create(client, cName, oNames[i], createOpts)
    55  		th.AssertNoErr(t, res.Err)
    56  	}
    57  	// Delete the objects after testing.
    58  	defer func() {
    59  		for i := 0; i < numObjects; i++ {
    60  			res := objects.Delete(client, cName, oNames[i], nil)
    61  			th.AssertNoErr(t, res.Err)
    62  		}
    63  	}()
    64  
    65  	// List all created objects
    66  	listOpts := objects.ListOpts{
    67  		Full:   true,
    68  		Prefix: "test-object-",
    69  	}
    70  
    71  	allPages, err := objects.List(client, cName, listOpts).AllPages()
    72  	if err != nil {
    73  		t.Fatalf("Unable to list objects: %v", err)
    74  	}
    75  
    76  	ons, err := objects.ExtractNames(allPages)
    77  	if err != nil {
    78  		t.Fatalf("Unable to extract objects: %v", err)
    79  	}
    80  	th.AssertEquals(t, len(ons), len(oNames))
    81  
    82  	ois, err := objects.ExtractInfo(allPages)
    83  	if err != nil {
    84  		t.Fatalf("Unable to extract object info: %v", err)
    85  	}
    86  	th.AssertEquals(t, len(ois), len(oNames))
    87  
    88  	// Create temporary URL, download its contents and compare with what was originally created.
    89  	// Downloading the URL validates it (this cannot be done in unit tests).
    90  	objURLs := make([]string, numObjects)
    91  	for i := 0; i < numObjects; i++ {
    92  		objURLs[i], err = objects.CreateTempURL(client, cName, oNames[i], objects.CreateTempURLOpts{
    93  			Method: http.MethodGet,
    94  			TTL:    180,
    95  		})
    96  		th.AssertNoErr(t, err)
    97  
    98  		resp, err := http.Get(objURLs[i])
    99  		th.AssertNoErr(t, err)
   100  
   101  		body, err := ioutil.ReadAll(resp.Body)
   102  		th.AssertNoErr(t, err)
   103  		th.AssertDeepEquals(t, oContents[i].Bytes(), body)
   104  		resp.Body.Close()
   105  	}
   106  
   107  	// Copy the contents of one object to another.
   108  	copyOpts := objects.CopyOpts{
   109  		Destination: cName + "/" + oNames[1],
   110  	}
   111  	copyres := objects.Copy(client, cName, oNames[0], copyOpts)
   112  	th.AssertNoErr(t, copyres.Err)
   113  
   114  	// Download one of the objects that was created above.
   115  	downloadres := objects.Download(client, cName, oNames[0], nil)
   116  	th.AssertNoErr(t, downloadres.Err)
   117  
   118  	o1Content, err := downloadres.ExtractContent()
   119  	th.AssertNoErr(t, err)
   120  
   121  	// Download the another object that was create above.
   122  	downloadOpts := objects.DownloadOpts{
   123  		Newest: true,
   124  	}
   125  	downloadres = objects.Download(client, cName, oNames[1], downloadOpts)
   126  	th.AssertNoErr(t, downloadres.Err)
   127  	o2Content, err := downloadres.ExtractContent()
   128  	th.AssertNoErr(t, err)
   129  
   130  	// Compare the two object's contents to test that the copy worked.
   131  	th.AssertEquals(t, string(o2Content), string(o1Content))
   132  
   133  	// Update an object's metadata.
   134  	metadata := map[string]string{
   135  		"Gophercloud-Test": "objects",
   136  	}
   137  
   138  	disposition := "inline"
   139  	cType := "text/plain"
   140  	updateOpts := &objects.UpdateOpts{
   141  		Metadata:           metadata,
   142  		ContentDisposition: &disposition,
   143  		ContentType:        &cType,
   144  	}
   145  	updateres := objects.Update(client, cName, oNames[0], updateOpts)
   146  	th.AssertNoErr(t, updateres.Err)
   147  
   148  	// Delete the object's metadata after testing.
   149  	defer func() {
   150  		temp := make([]string, len(metadata))
   151  		i := 0
   152  		for k := range metadata {
   153  			temp[i] = k
   154  			i++
   155  		}
   156  		empty := ""
   157  		cType := "application/octet-stream"
   158  		iTrue := true
   159  		updateOpts = &objects.UpdateOpts{
   160  			RemoveMetadata:     temp,
   161  			ContentDisposition: &empty,
   162  			ContentType:        &cType,
   163  			DetectContentType:  &iTrue,
   164  		}
   165  		res := objects.Update(client, cName, oNames[0], updateOpts)
   166  		th.AssertNoErr(t, res.Err)
   167  
   168  		// Retrieve an object's metadata.
   169  		getOpts := objects.GetOpts{
   170  			Newest: true,
   171  		}
   172  		resp := objects.Get(client, cName, oNames[0], getOpts)
   173  		om, err := resp.ExtractMetadata()
   174  		th.AssertNoErr(t, err)
   175  		if len(om) > 0 {
   176  			t.Errorf("Expected custom metadata to be empty, found: %v", metadata)
   177  		}
   178  		object, err := resp.Extract()
   179  		th.AssertNoErr(t, err)
   180  		th.AssertEquals(t, empty, object.ContentDisposition)
   181  		th.AssertEquals(t, cType, object.ContentType)
   182  	}()
   183  
   184  	// Retrieve an object's metadata.
   185  	getOpts := objects.GetOpts{
   186  		Newest: true,
   187  	}
   188  	resp := objects.Get(client, cName, oNames[0], getOpts)
   189  	om, err := resp.ExtractMetadata()
   190  	th.AssertNoErr(t, err)
   191  	for k := range metadata {
   192  		if om[k] != metadata[strings.Title(k)] {
   193  			t.Errorf("Expected custom metadata with key: %s", k)
   194  			return
   195  		}
   196  	}
   197  
   198  	object, err := resp.Extract()
   199  	th.AssertNoErr(t, err)
   200  	th.AssertEquals(t, disposition, object.ContentDisposition)
   201  	th.AssertEquals(t, cType, object.ContentType)
   202  }
   203  
   204  func TestObjectsListSubdir(t *testing.T) {
   205  	client, err := clients.NewObjectStorageV1Client()
   206  	if err != nil {
   207  		t.Fatalf("Unable to create client: %v", err)
   208  	}
   209  
   210  	// Create a random subdirectory name.
   211  	cSubdir1 := tools.RandomString("test-subdir-", 8)
   212  	cSubdir2 := tools.RandomString("test-subdir-", 8)
   213  
   214  	// Make a slice of length numObjects to hold the random object names.
   215  	oNames1 := make([]string, numObjects)
   216  	for i := 0; i < len(oNames1); i++ {
   217  		oNames1[i] = cSubdir1 + "/" + tools.RandomString("test-object-", 8)
   218  	}
   219  
   220  	oNames2 := make([]string, numObjects)
   221  	for i := 0; i < len(oNames2); i++ {
   222  		oNames2[i] = cSubdir2 + "/" + tools.RandomString("test-object-", 8)
   223  	}
   224  
   225  	// Create a container to hold the test objects.
   226  	cName := tools.RandomString("test-container-", 8)
   227  	_, err = containers.Create(client, cName, nil).Extract()
   228  	th.AssertNoErr(t, err)
   229  
   230  	// Defer deletion of the container until after testing.
   231  	defer func() {
   232  		t.Logf("Deleting container %s", cName)
   233  		res := containers.Delete(client, cName)
   234  		th.AssertNoErr(t, res.Err)
   235  	}()
   236  
   237  	// Create a slice of buffers to hold the test object content.
   238  	oContents1 := make([]*bytes.Buffer, numObjects)
   239  	for i := 0; i < numObjects; i++ {
   240  		oContents1[i] = bytes.NewBuffer([]byte(tools.RandomString("", 10)))
   241  		createOpts := objects.CreateOpts{
   242  			Content: oContents1[i],
   243  		}
   244  		res := objects.Create(client, cName, oNames1[i], createOpts)
   245  		th.AssertNoErr(t, res.Err)
   246  	}
   247  	// Delete the objects after testing.
   248  	defer func() {
   249  		for i := 0; i < numObjects; i++ {
   250  			t.Logf("Deleting object %s", oNames1[i])
   251  			res := objects.Delete(client, cName, oNames1[i], nil)
   252  			th.AssertNoErr(t, res.Err)
   253  		}
   254  	}()
   255  
   256  	oContents2 := make([]*bytes.Buffer, numObjects)
   257  	for i := 0; i < numObjects; i++ {
   258  		oContents2[i] = bytes.NewBuffer([]byte(tools.RandomString("", 10)))
   259  		createOpts := objects.CreateOpts{
   260  			Content: oContents2[i],
   261  		}
   262  		res := objects.Create(client, cName, oNames2[i], createOpts)
   263  		th.AssertNoErr(t, res.Err)
   264  	}
   265  	// Delete the objects after testing.
   266  	defer func() {
   267  		for i := 0; i < numObjects; i++ {
   268  			t.Logf("Deleting object %s", oNames2[i])
   269  			res := objects.Delete(client, cName, oNames2[i], nil)
   270  			th.AssertNoErr(t, res.Err)
   271  		}
   272  	}()
   273  
   274  	listOpts := objects.ListOpts{
   275  		Full:      true,
   276  		Delimiter: "/",
   277  	}
   278  
   279  	allPages, err := objects.List(client, cName, listOpts).AllPages()
   280  	if err != nil {
   281  		t.Fatal(err)
   282  	}
   283  
   284  	allObjects, err := objects.ExtractNames(allPages)
   285  	if err != nil {
   286  		t.Fatal(err)
   287  	}
   288  
   289  	t.Logf("%#v\n", allObjects)
   290  	expected := []string{cSubdir1, cSubdir2}
   291  	for _, e := range expected {
   292  		var valid bool
   293  		for _, a := range allObjects {
   294  			if e+"/" == a {
   295  				valid = true
   296  			}
   297  		}
   298  		if !valid {
   299  			t.Fatalf("could not find %s in results", e)
   300  		}
   301  	}
   302  
   303  	listOpts = objects.ListOpts{
   304  		Full:      true,
   305  		Delimiter: "/",
   306  		Prefix:    cSubdir2,
   307  	}
   308  
   309  	allPages, err = objects.List(client, cName, listOpts).AllPages()
   310  	if err != nil {
   311  		t.Fatal(err)
   312  	}
   313  
   314  	allObjects, err = objects.ExtractNames(allPages)
   315  	if err != nil {
   316  		t.Fatal(err)
   317  	}
   318  
   319  	th.AssertEquals(t, allObjects[0], cSubdir2+"/")
   320  	t.Logf("%#v\n", allObjects)
   321  }
   322  
   323  func TestObjectsBulkDelete(t *testing.T) {
   324  	client, err := clients.NewObjectStorageV1Client()
   325  	if err != nil {
   326  		t.Fatalf("Unable to create client: %v", err)
   327  	}
   328  
   329  	// Create a random subdirectory name.
   330  	cSubdir1 := tools.RandomString("test-subdir-", 8)
   331  	cSubdir2 := tools.RandomString("test-subdir-", 8)
   332  
   333  	// Make a slice of length numObjects to hold the random object names.
   334  	oNames1 := make([]string, numObjects)
   335  	for i := 0; i < len(oNames1); i++ {
   336  		oNames1[i] = cSubdir1 + "/" + tools.RandomString("test-object-", 8)
   337  	}
   338  
   339  	oNames2 := make([]string, numObjects)
   340  	for i := 0; i < len(oNames2); i++ {
   341  		oNames2[i] = cSubdir2 + "/" + tools.RandomString("test-object-", 8)
   342  	}
   343  
   344  	// Create a container to hold the test objects.
   345  	cName := tools.RandomString("test-container-", 8)
   346  	_, err = containers.Create(client, cName, nil).Extract()
   347  	th.AssertNoErr(t, err)
   348  
   349  	// Defer deletion of the container until after testing.
   350  	defer func() {
   351  		t.Logf("Deleting container %s", cName)
   352  		res := containers.Delete(client, cName)
   353  		th.AssertNoErr(t, res.Err)
   354  	}()
   355  
   356  	// Create a slice of buffers to hold the test object content.
   357  	oContents1 := make([]*bytes.Buffer, numObjects)
   358  	for i := 0; i < numObjects; i++ {
   359  		oContents1[i] = bytes.NewBuffer([]byte(tools.RandomString("", 10)))
   360  		createOpts := objects.CreateOpts{
   361  			Content: oContents1[i],
   362  		}
   363  		res := objects.Create(client, cName, oNames1[i], createOpts)
   364  		th.AssertNoErr(t, res.Err)
   365  	}
   366  
   367  	oContents2 := make([]*bytes.Buffer, numObjects)
   368  	for i := 0; i < numObjects; i++ {
   369  		oContents2[i] = bytes.NewBuffer([]byte(tools.RandomString("", 10)))
   370  		createOpts := objects.CreateOpts{
   371  			Content: oContents2[i],
   372  		}
   373  		res := objects.Create(client, cName, oNames2[i], createOpts)
   374  		th.AssertNoErr(t, res.Err)
   375  	}
   376  
   377  	// Delete the objects after testing.
   378  	expectedResp := objects.BulkDeleteResponse{
   379  		ResponseStatus: "200 OK",
   380  		Errors:         [][]string{},
   381  		NumberDeleted:  numObjects * 2,
   382  	}
   383  
   384  	resp, err := objects.BulkDelete(client, cName, append(oNames1, oNames2...)).Extract()
   385  	th.AssertNoErr(t, err)
   386  	th.AssertDeepEquals(t, *resp, expectedResp)
   387  
   388  	// Verify deletion
   389  	listOpts := objects.ListOpts{
   390  		Full:      true,
   391  		Delimiter: "/",
   392  	}
   393  
   394  	allPages, err := objects.List(client, cName, listOpts).AllPages()
   395  	if err != nil {
   396  		t.Fatal(err)
   397  	}
   398  
   399  	allObjects, err := objects.ExtractNames(allPages)
   400  	if err != nil {
   401  		t.Fatal(err)
   402  	}
   403  
   404  	th.AssertEquals(t, len(allObjects), 0)
   405  }