From fecec73901e549dc0cbd7b4afe0a109aa66439f3 Mon Sep 17 00:00:00 2001 From: Clyde Date: Thu, 21 Dec 2023 12:13:27 +0800 Subject: [PATCH 1/3] fix: remove tags field when creating object/group/bucket --- .github/workflows/e2e.yml | 4 +- client/api_bucket.go | 13 ++++-- client/api_group.go | 23 ++++++++++- client/api_object.go | 20 ++++++---- e2e/e2e_storage_test.go | 83 ++++++++++++++++++++++++++++++++++++++- go.mod | 4 +- go.sum | 4 +- 7 files changed, 131 insertions(+), 20 deletions(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 4effe535..3c41e3d2 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -12,8 +12,8 @@ on: - develop env: - GreenfieldTag: develop - GreenfieldStorageProviderTag: develop + GreenfieldTag: master + GreenfieldStorageProviderTag: fix-adapt-new-tag GOPRIVATE: github.com/bnb-chain GH_ACCESS_TOKEN: ${{ secrets.GH_TOKEN }} MYSQL_USER: root diff --git a/client/api_bucket.go b/client/api_bucket.go index f0d57c28..39e04ec2 100644 --- a/client/api_bucket.go +++ b/client/api_bucket.go @@ -153,9 +153,6 @@ func (c *Client) CreateBucket(ctx context.Context, bucketName string, primaryAdd } createBucketMsg := storageTypes.NewMsgCreateBucket(c.MustGetDefaultAccount().GetAddress(), bucketName, visibility, address, paymentAddr, 0, nil, opts.ChargedQuota) - if opts.Tags != nil { - createBucketMsg.Tags = *opts.Tags - } err = createBucketMsg.ValidateBasic() if err != nil { @@ -171,7 +168,15 @@ func (c *Client) CreateBucket(ctx context.Context, bucketName string, primaryAdd broadcastMode := tx.BroadcastMode_BROADCAST_MODE_SYNC opts.TxOpts = &gnfdsdk.TxOption{Mode: &broadcastMode} } - resp, err := c.BroadcastTx(ctx, []sdk.Msg{signedMsg}, opts.TxOpts) + msgs := []sdk.Msg{signedMsg} + + if opts.Tags != nil { + // Set tag + grn := gnfdTypes.NewBucketGRN(bucketName) + msgSetTag := storageTypes.NewMsgSetTag(c.MustGetDefaultAccount().GetAddress(), grn.String(), opts.Tags) + msgs = append(msgs, msgSetTag) + } + resp, err := c.BroadcastTx(ctx, msgs, opts.TxOpts) if err != nil { return "", err } diff --git a/client/api_group.go b/client/api_group.go index 3d2cf206..4ab6bb3b 100644 --- a/client/api_group.go +++ b/client/api_group.go @@ -14,10 +14,12 @@ import ( sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/tx" "github.com/rs/zerolog/log" "github.com/bnb-chain/greenfield-go-sdk/pkg/utils" "github.com/bnb-chain/greenfield-go-sdk/types" + gnfdsdk "github.com/bnb-chain/greenfield/sdk/types" gnfdTypes "github.com/bnb-chain/greenfield/types" permTypes "github.com/bnb-chain/greenfield/x/permission/types" storageTypes "github.com/bnb-chain/greenfield/x/storage/types" @@ -70,10 +72,27 @@ type IGroupClient interface { // - ret3: Return error when the request failed, otherwise return nil. func (c *Client) CreateGroup(ctx context.Context, groupName string, opt types.CreateGroupOptions) (string, error) { createGroupMsg := storageTypes.NewMsgCreateGroup(c.MustGetDefaultAccount().GetAddress(), groupName, opt.Extra) + // set the default txn broadcast mode as block mode + if opt.TxOpts == nil { + broadcastMode := tx.BroadcastMode_BROADCAST_MODE_SYNC + opt.TxOpts = &gnfdsdk.TxOption{Mode: &broadcastMode} + } + msgs := []sdk.Msg{createGroupMsg} + if opt.Tags != nil { - createGroupMsg.Tags = *opt.Tags + // Set tag + grn := gnfdTypes.NewGroupGRN(c.MustGetDefaultAccount().GetAddress(), groupName) + msgSetTag := storageTypes.NewMsgSetTag(c.MustGetDefaultAccount().GetAddress(), grn.String(), opt.Tags) + msgs = append(msgs, msgSetTag) } - return c.sendTxn(ctx, createGroupMsg, opt.TxOpts) + + resp, err := c.BroadcastTx(ctx, msgs, opt.TxOpts) + if err != nil { + return "", err + } + txnHash := resp.TxResponse.TxHash + + return txnHash, nil } // DeleteGroup - Delete a group on Greenfield blockchain. The sender MUST only be the group owner, group members or others would fail to send this transaction. diff --git a/client/api_object.go b/client/api_object.go index 18bcc9d3..259f5458 100644 --- a/client/api_object.go +++ b/client/api_object.go @@ -17,6 +17,10 @@ import ( "strings" "time" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/tx" + "github.com/rs/zerolog/log" + hashlib "github.com/bnb-chain/greenfield-common/go/hash" "github.com/bnb-chain/greenfield-go-sdk/pkg/utils" "github.com/bnb-chain/greenfield-go-sdk/types" @@ -25,9 +29,6 @@ import ( "github.com/bnb-chain/greenfield/types/s3util" permTypes "github.com/bnb-chain/greenfield/x/permission/types" storageTypes "github.com/bnb-chain/greenfield/x/storage/types" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/tx" - "github.com/rs/zerolog/log" ) // IObjectClient interface defines functions related to object operations. @@ -137,9 +138,6 @@ func (c *Client) CreateObject(ctx context.Context, bucketName, objectName string createObjectMsg := storageTypes.NewMsgCreateObject(c.MustGetDefaultAccount().GetAddress(), bucketName, objectName, uint64(size), visibility, expectCheckSums, contentType, redundancyType, math.MaxUint, nil) - if opts.Tags != nil { - createObjectMsg.Tags = *opts.Tags - } err = createObjectMsg.ValidateBasic() if err != nil { @@ -156,8 +154,16 @@ func (c *Client) CreateObject(ctx context.Context, bucketName, objectName string broadcastMode := tx.BroadcastMode_BROADCAST_MODE_SYNC opts.TxOpts = &gnfdsdk.TxOption{Mode: &broadcastMode} } + msgs := []sdk.Msg{signedCreateObjectMsg} + + if opts.Tags != nil { + // Set tag + grn := gnfdTypes.NewObjectGRN(bucketName, objectName) + msgSetTag := storageTypes.NewMsgSetTag(c.MustGetDefaultAccount().GetAddress(), grn.String(), opts.Tags) + msgs = append(msgs, msgSetTag) + } - resp, err := c.BroadcastTx(ctx, []sdk.Msg{signedCreateObjectMsg}, opts.TxOpts) + resp, err := c.BroadcastTx(ctx, msgs, opts.TxOpts) if err != nil { return "", err } diff --git a/e2e/e2e_storage_test.go b/e2e/e2e_storage_test.go index 83fba57c..86d9b33b 100644 --- a/e2e/e2e_storage_test.go +++ b/e2e/e2e_storage_test.go @@ -12,17 +12,19 @@ import ( "time" "cosmossdk.io/math" + "github.com/stretchr/testify/suite" + "github.com/bnb-chain/greenfield-go-sdk/client" "github.com/bnb-chain/greenfield-go-sdk/e2e/basesuite" "github.com/bnb-chain/greenfield-go-sdk/pkg/utils" "github.com/bnb-chain/greenfield-go-sdk/types" types2 "github.com/bnb-chain/greenfield/sdk/types" storageTestUtil "github.com/bnb-chain/greenfield/testutil/storage" + greenfield_types "github.com/bnb-chain/greenfield/types" "github.com/bnb-chain/greenfield/types/resource" permTypes "github.com/bnb-chain/greenfield/x/permission/types" spTypes "github.com/bnb-chain/greenfield/x/sp/types" storageTypes "github.com/bnb-chain/greenfield/x/storage/types" - "github.com/stretchr/testify/suite" ) type StorageTestSuite struct { @@ -626,3 +628,82 @@ func (s *StorageTestSuite) Test_Upload_Object_With_Tampering_Content() { s.Require().Equal(objectDetail.ObjectInfo.ObjectName, objectName) s.Require().Equal(objectDetail.ObjectInfo.GetObjectStatus().String(), "OBJECT_STATUS_CREATED") } + +func (s *StorageTestSuite) Test_Group_with_Tag() { + //create group with tag + groupName := storageTestUtil.GenRandomGroupName() + + groupOwner := s.DefaultAccount.GetAddress() + s.T().Log("---> CreateGroup and HeadGroup <---") + + var tags storageTypes.ResourceTags + tags.Tags = append(tags.Tags, storageTypes.ResourceTags_Tag{Key: "key1", Value: "value1"}) + tags.Tags = append(tags.Tags, storageTypes.ResourceTags_Tag{Key: "key2", Value: "value2"}) + + _, err := s.Client.CreateGroup(s.ClientContext, groupName, types.CreateGroupOptions{Tags: &tags}) + s.Require().NoError(err) + s.T().Logf("create GroupName: %s", groupName) + + time.Sleep(5 * time.Second) + headResult, err := s.Client.HeadGroup(s.ClientContext, groupName, groupOwner.String()) + s.Require().NoError(err) + s.Require().Equal(groupName, headResult.GroupName) + s.Require().Equal(tags, &headResult.Tags) +} + +func (s *StorageTestSuite) Test_Group_without_Tag() { + //create group with tag + groupName := storageTestUtil.GenRandomGroupName() + + groupOwner := s.DefaultAccount.GetAddress() + s.T().Log("---> CreateGroup and HeadGroup <---") + + _, err := s.Client.CreateGroup(s.ClientContext, groupName, types.CreateGroupOptions{}) + s.Require().NoError(err) + s.T().Logf("create GroupName: %s", groupName) + + time.Sleep(5 * time.Second) + headResult, err := s.Client.HeadGroup(s.ClientContext, groupName, groupOwner.String()) + s.Require().NoError(err) + s.Require().Equal(groupName, headResult.GroupName) + + grn := greenfield_types.NewGroupGRN(groupOwner, groupName) + var tags storageTypes.ResourceTags + tags.Tags = append(tags.Tags, storageTypes.ResourceTags_Tag{Key: "key1", Value: "value1"}) + tags.Tags = append(tags.Tags, storageTypes.ResourceTags_Tag{Key: "key2", Value: "value2"}) + + _, err = s.Client.SetTag(s.ClientContext, grn.String(), tags, types.SetTagsOptions{}) + s.Require().NoError(err) + s.T().Logf("set tag: %v for group %s", tags, groupName) + + time.Sleep(5 * time.Second) + headResult, err = s.Client.HeadGroup(s.ClientContext, groupName, groupOwner.String()) + s.Require().NoError(err) + s.Require().Equal(groupName, headResult.GroupName) + s.Require().Equal(tags, &headResult.Tags) +} + +func (s *StorageTestSuite) Test_Bucket_with_Tag() { + bucketName := storageTestUtil.GenRandomBucketName() + var tags storageTypes.ResourceTags + tags.Tags = append(tags.Tags, storageTypes.ResourceTags_Tag{Key: "key1", Value: "value1"}) + tags.Tags = append(tags.Tags, storageTypes.ResourceTags_Tag{Key: "key2", Value: "value2"}) + + chargedQuota := uint64(100) + s.T().Log("---> CreateBucket and HeadBucket <---") + opts := types.CreateBucketOptions{ChargedQuota: chargedQuota, Tags: &tags} + + bucketTx, err := s.Client.CreateBucket(s.ClientContext, bucketName, s.PrimarySP.OperatorAddress, opts) + s.Require().NoError(err) + + _, err = s.Client.WaitForTx(s.ClientContext, bucketTx) + s.Require().NoError(err) + + bucketInfo, err := s.Client.HeadBucket(s.ClientContext, bucketName) + s.Require().NoError(err) + if err == nil { + s.Require().Equal(bucketInfo.Visibility, storageTypes.VISIBILITY_TYPE_PRIVATE) + s.Require().Equal(bucketInfo.ChargedReadQuota, chargedQuota) + s.Require().Equal(tags, &bucketInfo.Tags) + } +} diff --git a/go.mod b/go.mod index d7935b4a..50f62533 100644 --- a/go.mod +++ b/go.mod @@ -5,11 +5,12 @@ go 1.20 require ( cosmossdk.io/errors v1.0.0-beta.7 cosmossdk.io/math v1.0.1 - github.com/bnb-chain/greenfield v1.0.2-0.20231205022545-1760620afde0 + github.com/bnb-chain/greenfield v1.2.1-0.20231221015040-11071a6ee95b github.com/bnb-chain/greenfield-common/go v0.0.0-20230906132736-eb2f0efea228 github.com/cometbft/cometbft v0.37.2 github.com/consensys/gnark-crypto v0.7.0 github.com/cosmos/cosmos-sdk v0.47.3 + github.com/cosmos/gogoproto v1.4.10 github.com/ethereum/go-ethereum v1.10.26 github.com/prysmaticlabs/prysm v0.0.0-20220124113610-e26cde5e091b github.com/rs/zerolog v1.29.1 @@ -40,7 +41,6 @@ require ( github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/cosmos-proto v1.0.0-beta.3 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect - github.com/cosmos/gogoproto v1.4.10 // indirect github.com/cosmos/iavl v0.20.0 // indirect github.com/cosmos/ledger-cosmos-go v0.13.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect diff --git a/go.sum b/go.sum index ca400654..cdafd36c 100644 --- a/go.sum +++ b/go.sum @@ -152,8 +152,8 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 h1:41iFGWnSlI2gVpmOtVTJZNodLdLQLn/KsJqFvXwnd/s= github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c= -github.com/bnb-chain/greenfield v1.0.2-0.20231205022545-1760620afde0 h1:dnwMwE6IVg54Jzeaa8fN+BbLBJWVPcURs/2hKZipRuk= -github.com/bnb-chain/greenfield v1.0.2-0.20231205022545-1760620afde0/go.mod h1:hF7FWoXDx3ddImH3OGUNrlTdwkWKNIYUOGL+Yrq0nsg= +github.com/bnb-chain/greenfield v1.2.1-0.20231221015040-11071a6ee95b h1:UBgGcMo5Sf+sCMqkB2zu0sfuuMGBQ+5Ib1QIJ0sLXes= +github.com/bnb-chain/greenfield v1.2.1-0.20231221015040-11071a6ee95b/go.mod h1:p8M80v/a6mRm+ZPbW8Hfjc1npWktO6BDtebr9/8ETRs= github.com/bnb-chain/greenfield-cometbft v1.1.0 h1:jqnkDWIZW6f/rUn5/pE26YZMT9xzpp0qTswNy7FPRBk= github.com/bnb-chain/greenfield-cometbft v1.1.0/go.mod h1:NZ2/ZJK2HYe3++0CsPiw4LTG6UrC6pH7fQ3VOz6pqJw= github.com/bnb-chain/greenfield-cometbft-db v0.8.1-alpha.1 h1:XcWulGacHVRiSCx90Q8Y//ajOrLNBQWR/KDB89dy3cU= From a9a294ef931bc9f50430d8153cef03a672bcc436 Mon Sep 17 00:00:00 2001 From: Clyde Date: Thu, 21 Dec 2023 12:29:35 +0800 Subject: [PATCH 2/3] fix: e2e --- e2e/e2e_storage_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/e2e/e2e_storage_test.go b/e2e/e2e_storage_test.go index 86d9b33b..7a2bbd8f 100644 --- a/e2e/e2e_storage_test.go +++ b/e2e/e2e_storage_test.go @@ -648,7 +648,7 @@ func (s *StorageTestSuite) Test_Group_with_Tag() { headResult, err := s.Client.HeadGroup(s.ClientContext, groupName, groupOwner.String()) s.Require().NoError(err) s.Require().Equal(groupName, headResult.GroupName) - s.Require().Equal(tags, &headResult.Tags) + s.Require().Equal(tags, *headResult.Tags) } func (s *StorageTestSuite) Test_Group_without_Tag() { @@ -680,7 +680,7 @@ func (s *StorageTestSuite) Test_Group_without_Tag() { headResult, err = s.Client.HeadGroup(s.ClientContext, groupName, groupOwner.String()) s.Require().NoError(err) s.Require().Equal(groupName, headResult.GroupName) - s.Require().Equal(tags, &headResult.Tags) + s.Require().Equal(tags, *headResult.Tags) } func (s *StorageTestSuite) Test_Bucket_with_Tag() { @@ -704,6 +704,6 @@ func (s *StorageTestSuite) Test_Bucket_with_Tag() { if err == nil { s.Require().Equal(bucketInfo.Visibility, storageTypes.VISIBILITY_TYPE_PRIVATE) s.Require().Equal(bucketInfo.ChargedReadQuota, chargedQuota) - s.Require().Equal(tags, &bucketInfo.Tags) + s.Require().Equal(tags, *bucketInfo.Tags) } } From 746707308b1d71ffb23e976cbb4efd4906c92738 Mon Sep 17 00:00:00 2001 From: Clyde Date: Thu, 21 Dec 2023 15:44:04 +0800 Subject: [PATCH 3/3] fix: add more e2e cases --- e2e/e2e_storage_test.go | 139 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 138 insertions(+), 1 deletion(-) diff --git a/e2e/e2e_storage_test.go b/e2e/e2e_storage_test.go index 7a2bbd8f..4fb0672e 100644 --- a/e2e/e2e_storage_test.go +++ b/e2e/e2e_storage_test.go @@ -651,7 +651,7 @@ func (s *StorageTestSuite) Test_Group_with_Tag() { s.Require().Equal(tags, *headResult.Tags) } -func (s *StorageTestSuite) Test_Group_without_Tag() { +func (s *StorageTestSuite) Test_CreateGroup_And_Set_Tag() { //create group with tag groupName := storageTestUtil.GenRandomGroupName() @@ -707,3 +707,140 @@ func (s *StorageTestSuite) Test_Bucket_with_Tag() { s.Require().Equal(tags, *bucketInfo.Tags) } } + +func (s *StorageTestSuite) Test_CreateBucket_And_Set_Tag() { + bucketName := storageTestUtil.GenRandomBucketName() + + chargedQuota := uint64(100) + s.T().Log("---> CreateBucket and HeadBucket <---") + opts := types.CreateBucketOptions{ChargedQuota: chargedQuota} + + bucketTx, err := s.Client.CreateBucket(s.ClientContext, bucketName, s.PrimarySP.OperatorAddress, opts) + s.Require().NoError(err) + + _, err = s.Client.WaitForTx(s.ClientContext, bucketTx) + s.Require().NoError(err) + + bucketInfo, err := s.Client.HeadBucket(s.ClientContext, bucketName) + s.Require().NoError(err) + if err == nil { + s.Require().Equal(bucketInfo.Visibility, storageTypes.VISIBILITY_TYPE_PRIVATE) + s.Require().Equal(bucketInfo.ChargedReadQuota, chargedQuota) + } + + // set tag + grn := greenfield_types.NewBucketGRN(bucketName) + var tags storageTypes.ResourceTags + tags.Tags = append(tags.Tags, storageTypes.ResourceTags_Tag{Key: "key1", Value: "value1"}) + tags.Tags = append(tags.Tags, storageTypes.ResourceTags_Tag{Key: "key2", Value: "value2"}) + + _, err = s.Client.SetTag(s.ClientContext, grn.String(), tags, types.SetTagsOptions{}) + s.Require().NoError(err) + s.T().Logf("set tag: %v for bucket %s", tags, bucketName) + + time.Sleep(5 * time.Second) + bucketInfo, err = s.Client.HeadBucket(s.ClientContext, bucketName) + s.Require().NoError(err) + if err == nil { + s.Require().Equal(tags, *bucketInfo.Tags) + } +} + +func (s *StorageTestSuite) Test_Object_with_Tag() { + bucketName := storageTestUtil.GenRandomBucketName() + objectName := storageTestUtil.GenRandomObjectName() + + s.T().Logf("BucketName:%s, objectName: %s", bucketName, objectName) + + bucketTx, err := s.Client.CreateBucket(s.ClientContext, bucketName, s.PrimarySP.OperatorAddress, types.CreateBucketOptions{}) + s.Require().NoError(err) + + _, err = s.Client.WaitForTx(s.ClientContext, bucketTx) + s.Require().NoError(err) + + bucketInfo, err := s.Client.HeadBucket(s.ClientContext, bucketName) + s.Require().NoError(err) + if err == nil { + s.Require().Equal(bucketInfo.Visibility, storageTypes.VISIBILITY_TYPE_PRIVATE) + } + + var buffer bytes.Buffer + line := `1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,123456789012` + // Create 1MiB content where each line contains 1024 characters. + for i := 0; i < 1024*300; i++ { + buffer.WriteString(fmt.Sprintf("[%05d] %s\n", i, line)) + } + + var tags storageTypes.ResourceTags + tags.Tags = append(tags.Tags, storageTypes.ResourceTags_Tag{Key: "key1", Value: "value1"}) + tags.Tags = append(tags.Tags, storageTypes.ResourceTags_Tag{Key: "key2", Value: "value2"}) + s.T().Log("---> CreateObject and HeadObject <---") + objectTx, err := s.Client.CreateObject(s.ClientContext, bucketName, objectName, bytes.NewReader(buffer.Bytes()), + types.CreateObjectOptions{Tags: &tags}) + s.Require().NoError(err) + _, err = s.Client.WaitForTx(s.ClientContext, objectTx) + s.Require().NoError(err) + + time.Sleep(5 * time.Second) + objectDetail, err := s.Client.HeadObject(s.ClientContext, bucketName, objectName) + s.Require().NoError(err) + s.Require().Equal(objectDetail.ObjectInfo.ObjectName, objectName) + s.Require().Equal(objectDetail.ObjectInfo.GetObjectStatus().String(), "OBJECT_STATUS_CREATED") + s.Require().Equal(tags, *objectDetail.ObjectInfo.Tags) +} + +func (s *StorageTestSuite) Test_Object_And_Set_Tag() { + bucketName := storageTestUtil.GenRandomBucketName() + objectName := storageTestUtil.GenRandomObjectName() + + s.T().Logf("BucketName:%s, objectName: %s", bucketName, objectName) + + bucketTx, err := s.Client.CreateBucket(s.ClientContext, bucketName, s.PrimarySP.OperatorAddress, types.CreateBucketOptions{}) + s.Require().NoError(err) + + _, err = s.Client.WaitForTx(s.ClientContext, bucketTx) + s.Require().NoError(err) + + bucketInfo, err := s.Client.HeadBucket(s.ClientContext, bucketName) + s.Require().NoError(err) + if err == nil { + s.Require().Equal(bucketInfo.Visibility, storageTypes.VISIBILITY_TYPE_PRIVATE) + } + + var buffer bytes.Buffer + line := `1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,123456789012` + // Create 1MiB content where each line contains 1024 characters. + for i := 0; i < 1024*300; i++ { + buffer.WriteString(fmt.Sprintf("[%05d] %s\n", i, line)) + } + + s.T().Log("---> CreateObject and HeadObject <---") + objectTx, err := s.Client.CreateObject(s.ClientContext, bucketName, objectName, bytes.NewReader(buffer.Bytes()), + types.CreateObjectOptions{}) + s.Require().NoError(err) + _, err = s.Client.WaitForTx(s.ClientContext, objectTx) + s.Require().NoError(err) + + time.Sleep(5 * time.Second) + objectDetail, err := s.Client.HeadObject(s.ClientContext, bucketName, objectName) + s.Require().NoError(err) + s.Require().Equal(objectDetail.ObjectInfo.ObjectName, objectName) + s.Require().Equal(objectDetail.ObjectInfo.GetObjectStatus().String(), "OBJECT_STATUS_CREATED") + + // set tag + grn := greenfield_types.NewObjectGRN(bucketName, objectName) + var tags storageTypes.ResourceTags + tags.Tags = append(tags.Tags, storageTypes.ResourceTags_Tag{Key: "key1", Value: "value1"}) + tags.Tags = append(tags.Tags, storageTypes.ResourceTags_Tag{Key: "key2", Value: "value2"}) + + _, err = s.Client.SetTag(s.ClientContext, grn.String(), tags, types.SetTagsOptions{}) + s.Require().NoError(err) + s.T().Logf("set tag: %v for object %s", tags, objectName) + + time.Sleep(5 * time.Second) + objectDetail, err = s.Client.HeadObject(s.ClientContext, bucketName, objectName) + s.Require().NoError(err) + if err == nil { + s.Require().Equal(tags, *objectDetail.ObjectInfo.Tags) + } +}