Skip to content

Commit 40f7a7f

Browse files
authored
Refactor handling of setting file expiry policy (#21378)
* Refactor handling of setting file expiry policy Switch to using a struct containing explicit fields instead of an interface to improve discovery and self-documentation. * fix lint * reverse order of fields
1 parent 8fd0022 commit 40f7a7f

File tree

6 files changed

+116
-159
lines changed

6 files changed

+116
-159
lines changed

sdk/storage/azdatalake/file/client.go

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,15 @@ import (
1010
"bytes"
1111
"context"
1212
"errors"
13+
"io"
14+
"net/http"
15+
"net/url"
16+
"os"
17+
"reflect"
18+
"strings"
19+
"sync"
20+
"time"
21+
1322
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
1423
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
1524
"github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
@@ -25,13 +34,6 @@ import (
2534
"github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/internal/path"
2635
"github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/internal/shared"
2736
"github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/sas"
28-
"io"
29-
"net/http"
30-
"net/url"
31-
"os"
32-
"strings"
33-
"sync"
34-
"time"
3537
)
3638

3739
// ClientOptions contains the optional parameters when creating a Client.
@@ -259,9 +261,15 @@ func (f *Client) Rename(ctx context.Context, newName string, options *RenameOpti
259261
}
260262

261263
// SetExpiry operation sets an expiry time on an existing file (blob2).
262-
func (f *Client) SetExpiry(ctx context.Context, expiryType SetExpiryType, o *SetExpiryOptions) (SetExpiryResponse, error) {
263-
expMode, opts := expiryType.Format(o)
264-
resp, err := f.generatedFileClientWithBlob().SetExpiry(ctx, expMode, opts)
264+
func (f *Client) SetExpiry(ctx context.Context, expiryValues SetExpiryValues, o *SetExpiryOptions) (SetExpiryResponse, error) {
265+
if reflect.ValueOf(expiryValues).IsZero() {
266+
expiryValues.ExpiryType = SetExpiryTypeNeverExpire
267+
}
268+
opts := &generated_blob.BlobClientSetExpiryOptions{}
269+
if expiryValues.ExpiryType != SetExpiryTypeNeverExpire {
270+
opts.ExpiresOn = &expiryValues.ExpiresOn
271+
}
272+
resp, err := f.generatedFileClientWithBlob().SetExpiry(ctx, expiryValues.ExpiryType, opts)
265273
err = exported.ConvertToDFSError(err)
266274
return resp, err
267275
}

sdk/storage/azdatalake/file/client_test.go

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,15 @@ import (
1111
"context"
1212
"crypto/md5"
1313
"encoding/binary"
14+
"hash/crc64"
15+
"io"
16+
"math/rand"
17+
"net/http"
18+
"os"
19+
"strconv"
20+
"testing"
21+
"time"
22+
1423
"github.com/Azure/azure-sdk-for-go/sdk/azcore/streaming"
1524
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
1625
"github.com/Azure/azure-sdk-for-go/sdk/internal/recording"
@@ -21,13 +30,6 @@ import (
2130
"github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/sas"
2231
"github.com/stretchr/testify/require"
2332
"github.com/stretchr/testify/suite"
24-
"hash/crc64"
25-
"io"
26-
"math/rand"
27-
"net/http"
28-
"os"
29-
"testing"
30-
"time"
3133
)
3234

3335
var proposedLeaseIDs = []*string{to.Ptr("c820a799-76d7-4ee2-6e15-546f19325c2c"), to.Ptr("326cc5e1-746e-4af8-4811-a50e6629a8ca")}
@@ -472,9 +474,11 @@ func (s *UnrecordedTestSuite) TestCreateFileWithExpiryAbsolute() {
472474
defer testcommon.DeleteFilesystem(context.Background(), _require, fsClient)
473475

474476
expiryTimeAbsolute := time.Now().Add(8 * time.Second)
475-
expiry := file.CreationExpiryTypeAbsolute(expiryTimeAbsolute)
476477
createFileOpts := &file.CreateOptions{
477-
Expiry: expiry,
478+
Expiry: file.CreateExpiryValues{
479+
ExpiryType: file.CreateExpiryTypeAbsolute,
480+
ExpiresOn: time.Now().Add(8 * time.Second).UTC().Format(http.TimeFormat),
481+
},
478482
}
479483

480484
_, err = fsClient.Create(context.Background(), nil)
@@ -505,9 +509,11 @@ func (s *RecordedTestSuite) TestCreateFileWithExpiryRelativeToNow() {
505509
_require.NoError(err)
506510
defer testcommon.DeleteFilesystem(context.Background(), _require, fsClient)
507511

508-
expiry := file.CreationExpiryTypeRelativeToNow(8 * time.Second)
509512
createFileOpts := &file.CreateOptions{
510-
Expiry: expiry,
513+
Expiry: file.CreateExpiryValues{
514+
ExpiryType: file.CreateExpiryTypeRelativeToNow,
515+
ExpiresOn: strconv.FormatInt((8 * time.Second).Milliseconds(), 10),
516+
},
511517
}
512518

513519
_, err = fsClient.Create(context.Background(), nil)
@@ -540,7 +546,9 @@ func (s *RecordedTestSuite) TestCreateFileWithNeverExpire() {
540546
defer testcommon.DeleteFilesystem(context.Background(), _require, fsClient)
541547

542548
createFileOpts := &file.CreateOptions{
543-
Expiry: file.CreationExpiryTypeNever{},
549+
Expiry: file.CreateExpiryValues{
550+
ExpiryType: file.CreateExpiryTypeNeverExpire,
551+
},
544552
}
545553

546554
_, err = fsClient.Create(context.Background(), nil)
@@ -2961,6 +2969,7 @@ func (s *RecordedTestSuite) TestFileAppendAndFlushAndDownloadDataWithLeasedFile(
29612969
_require.Nil(err)
29622970

29632971
_, err = rsc.Seek(0, io.SeekStart)
2972+
_require.NoError(err)
29642973

29652974
_, err = srcFClient.AppendData(context.Background(), int64(contentSize), rsc, opts)
29662975
_require.Nil(err)

sdk/storage/azdatalake/file/constants.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ package file
99
import (
1010
"github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake"
1111
"github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/internal/exported"
12+
"github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/internal/generated"
13+
"github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/internal/generated_blob"
1214
"github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/internal/path"
1315
)
1416

@@ -50,6 +52,40 @@ func TransferValidationTypeComputeCRC64() TransferValidationType {
5052
return exported.TransferValidationTypeComputeCRC64()
5153
}
5254

55+
// SetExpiryType defines the values for modes of file expiration.
56+
type SetExpiryType = generated_blob.ExpiryOptions
57+
58+
const (
59+
// SetExpiryTypeAbsolute sets the expiration date as an absolute value expressed in RFC1123 format.
60+
SetExpiryTypeAbsolute SetExpiryType = generated_blob.ExpiryOptionsAbsolute
61+
62+
// SetExpiryTypeNeverExpire sets the file to never expire or removes the current expiration date.
63+
SetExpiryTypeNeverExpire SetExpiryType = generated_blob.ExpiryOptionsNeverExpire
64+
65+
// SetExpiryTypeRelativeToCreation sets the expiration date relative to the time of file creation.
66+
// The value is expressed as the number of miliseconds to elapse from the time of creation.
67+
SetExpiryTypeRelativeToCreation SetExpiryType = generated_blob.ExpiryOptionsRelativeToCreation
68+
69+
// SetExpiryTypeRelativeToNow sets the expiration date relative to the current time.
70+
// The value is expressed as the number of milliseconds to elapse from the present time.
71+
SetExpiryTypeRelativeToNow SetExpiryType = generated_blob.ExpiryOptionsRelativeToNow
72+
)
73+
74+
// CreateExpiryType defines the values for modes of file expiration specified during creation.
75+
type CreateExpiryType = generated.PathExpiryOptions
76+
77+
const (
78+
// CreateExpiryTypeAbsolute sets the expiration date as an absolute value expressed in RFC1123 format.
79+
CreateExpiryTypeAbsolute CreateExpiryType = generated.PathExpiryOptionsAbsolute
80+
81+
// CreateExpiryTypeNeverExpire sets the file to never expire or removes the current expiration date.
82+
CreateExpiryTypeNeverExpire CreateExpiryType = generated.PathExpiryOptionsNeverExpire
83+
84+
// CreateExpiryTypeRelativeToNow sets the expiration date relative to the current time.
85+
// The value is expressed as the number of milliseconds to elapse from the present time.
86+
CreateExpiryTypeRelativeToNow CreateExpiryType = generated.PathExpiryOptionsRelativeToNow
87+
)
88+
5389
// StatusType defines values for StatusType
5490
type StatusType = azdatalake.StatusType
5591

sdk/storage/azdatalake/file/models.go

Lines changed: 33 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,14 @@ package file
88

99
import (
1010
"errors"
11-
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
11+
"io"
12+
"reflect"
13+
1214
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob"
1315
"github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/internal/exported"
1416
"github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/internal/generated"
1517
"github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/internal/path"
1618
"github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/internal/shared"
17-
"io"
18-
"net/http"
19-
"strconv"
20-
"time"
2119
)
2220

2321
const (
@@ -42,7 +40,7 @@ type CreateOptions struct {
4240
// HTTPHeaders contains the HTTP headers for path operations.
4341
HTTPHeaders *HTTPHeaders
4442
// Expiry specifies the type and time of expiry for the file.
45-
Expiry CreationExpiryType
43+
Expiry CreateExpiryValues
4644
// LeaseDuration specifies the duration of the lease, in seconds, or negative one
4745
// (-1) for a lease that never expires. A non-infinite lease can be
4846
// between 15 and 60 seconds.
@@ -61,6 +59,18 @@ type CreateOptions struct {
6159
ACL *string
6260
}
6361

62+
// CreateExpiryValues describes when a newly created file should expire.
63+
// A zero-value indicates the file has no expiration date.
64+
type CreateExpiryValues struct {
65+
// ExpiryType indicates how the value of ExpiresOn should be interpreted (absolute, relative to now, etc).
66+
ExpiryType CreateExpiryType
67+
68+
// ExpiresOn contains the time the file should expire.
69+
// The value will either be an absolute UTC time in RFC1123 format or an integer expressing a number of milliseconds.
70+
// NOTE: when ExpiryType is CreateExpiryTypeNeverExpire, this value is ignored.
71+
ExpiresOn string
72+
}
73+
6474
func (o *CreateOptions) format() (*generated.LeaseAccessConditions, *generated.ModifiedAccessConditions, *generated.PathHTTPHeaders, *generated.PathClientCreateOptions, *generated.CPKInfo) {
6575
resource := generated.PathResourceTypeFile
6676
createOpts := &generated.PathClientCreateOptions{
@@ -70,13 +80,11 @@ func (o *CreateOptions) format() (*generated.LeaseAccessConditions, *generated.M
7080
return nil, nil, nil, createOpts, nil
7181
}
7282
leaseAccessConditions, modifiedAccessConditions := exported.FormatPathAccessConditions(o.AccessConditions)
73-
if o.Expiry == nil {
74-
createOpts.ExpiryOptions = nil
75-
createOpts.ExpiresOn = nil
76-
} else {
77-
expOpts, expiresOn := o.Expiry.Format()
78-
createOpts.ExpiryOptions = (*generated.PathExpiryOptions)(&expOpts)
79-
createOpts.ExpiresOn = expiresOn
83+
if !reflect.ValueOf(o.Expiry).IsZero() {
84+
createOpts.ExpiryOptions = &o.Expiry.ExpiryType
85+
if o.Expiry.ExpiryType != CreateExpiryTypeNeverExpire {
86+
createOpts.ExpiresOn = &o.Expiry.ExpiresOn
87+
}
8088
}
8189
createOpts.ACL = o.ACL
8290
createOpts.Group = o.Group
@@ -491,65 +499,28 @@ func (o *DownloadFileOptions) format() *blob.DownloadFileOptions {
491499
return downloadFileOptions
492500
}
493501

494-
// CreationExpiryType defines values for Create() ExpiryType
495-
type CreationExpiryType interface {
496-
Format() (generated.ExpiryOptions, *string)
497-
notPubliclyImplementable()
498-
}
499-
500-
// CreationExpiryTypeAbsolute defines the absolute time for the blob expiry
501-
type CreationExpiryTypeAbsolute time.Time
502-
503-
// CreationExpiryTypeRelativeToNow defines the duration relative to now for the blob expiry
504-
type CreationExpiryTypeRelativeToNow time.Duration
505-
506-
// CreationExpiryTypeNever defines that the blob will be set to never expire
507-
type CreationExpiryTypeNever struct {
508-
// empty struct since NeverExpire expiry type does not require expiry time
509-
}
510-
511-
func (e CreationExpiryTypeAbsolute) Format() (generated.ExpiryOptions, *string) {
512-
return generated.ExpiryOptionsAbsolute, to.Ptr(time.Time(e).UTC().Format(http.TimeFormat))
502+
// SetExpiryValues describes when a file should expire.
503+
// A zero-value indicates the file has no expiration date.
504+
type SetExpiryValues struct {
505+
// ExpiryType indicates how the value of ExpiresOn should be interpreted (absolute, relative to now, etc).
506+
ExpiryType SetExpiryType
513507

508+
// ExpiresOn contains the time the file should expire.
509+
// The value will either be an absolute UTC time in RFC1123 format or an integer expressing a number of milliseconds.
510+
// NOTE: when ExpiryType is SetExpiryTypeNeverExpire, this value is ignored.
511+
ExpiresOn string
514512
}
515513

516-
func (e CreationExpiryTypeAbsolute) notPubliclyImplementable() {}
517-
518-
func (e CreationExpiryTypeRelativeToNow) Format() (generated.ExpiryOptions, *string) {
519-
return generated.ExpiryOptionsRelativeToNow, to.Ptr(strconv.FormatInt(time.Duration(e).Milliseconds(), 10))
520-
}
521-
522-
func (e CreationExpiryTypeRelativeToNow) notPubliclyImplementable() {}
523-
524-
func (e CreationExpiryTypeNever) Format() (generated.ExpiryOptions, *string) {
525-
return generated.ExpiryOptionsNeverExpire, nil
526-
}
527-
528-
func (e CreationExpiryTypeNever) notPubliclyImplementable() {}
529-
530514
// ACLFailedEntry contains the failed ACL entry (response model).
531515
type ACLFailedEntry = path.ACLFailedEntry
532516

533517
// SetAccessControlRecursiveResponse contains part of the response data returned by the []OP_AccessControl operations.
534518
type SetAccessControlRecursiveResponse = generated.SetAccessControlRecursiveResponse
535519

536-
// SetExpiryType defines values for ExpiryType.
537-
type SetExpiryType = exported.SetExpiryType
538-
539-
// SetExpiryTypeAbsolute defines the absolute time for the expiry.
540-
type SetExpiryTypeAbsolute = exported.SetExpiryTypeAbsolute
541-
542-
// SetExpiryTypeRelativeToNow defines the duration relative to now for the expiry.
543-
type SetExpiryTypeRelativeToNow = exported.SetExpiryTypeRelativeToNow
544-
545-
// SetExpiryTypeRelativeToCreation defines the duration relative to creation for the expiry.
546-
type SetExpiryTypeRelativeToCreation = exported.SetExpiryTypeRelativeToCreation
547-
548-
// SetExpiryTypeNever defines that will be set to never expire.
549-
type SetExpiryTypeNever = exported.SetExpiryTypeNever
550-
551520
// SetExpiryOptions contains the optional parameters for the Client.SetExpiry method.
552-
type SetExpiryOptions = exported.SetExpiryOptions
521+
type SetExpiryOptions struct {
522+
// placeholder for future options
523+
}
553524

554525
type HTTPRange = exported.HTTPRange
555526

sdk/storage/azdatalake/filesystem/client_test.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ package filesystem_test
88

99
import (
1010
"context"
11+
"strconv"
12+
"strings"
13+
"testing"
14+
"time"
15+
1116
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
1217
"github.com/Azure/azure-sdk-for-go/sdk/internal/recording"
1318
"github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/datalakeerror"
@@ -17,10 +22,6 @@ import (
1722
"github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/sas"
1823
"github.com/stretchr/testify/require"
1924
"github.com/stretchr/testify/suite"
20-
"strconv"
21-
"strings"
22-
"testing"
23-
"time"
2425
)
2526

2627
func Test(t *testing.T) {
@@ -100,6 +101,7 @@ func (s *RecordedTestSuite) TestCreateFilesystemWithOptions() {
100101
_require.Nil(err)
101102

102103
props, err := fsClient.GetProperties(context.Background(), nil)
104+
_require.NoError(err)
103105
_require.NotNil(props.Metadata)
104106
_require.Equal(*props.PublicAccess, filesystem.Filesystem)
105107
}
@@ -123,6 +125,7 @@ func (s *RecordedTestSuite) TestCreateFilesystemWithFileAccess() {
123125
_, err = fsClient.Create(context.Background(), &opts)
124126
_require.Nil(err)
125127
props, err := fsClient.GetProperties(context.Background(), nil)
128+
_require.NoError(err)
126129
_require.NotNil(props.Metadata)
127130
_require.Equal(*props.PublicAccess, filesystem.File)
128131
}
@@ -146,6 +149,7 @@ func (s *RecordedTestSuite) TestCreateFilesystemEmptyMetadata() {
146149
_require.Nil(err)
147150

148151
props, err := fsClient.GetProperties(context.Background(), nil)
152+
_require.NoError(err)
149153
_require.Nil(props.Metadata)
150154
_require.Equal(*props.PublicAccess, filesystem.Filesystem)
151155

0 commit comments

Comments
 (0)