Skip to content

Commit 8aec227

Browse files
authored
Automatically create the hash data directory when using an alternative (#2611)
* Automatically create the hash data directory when using an alternative * Remove sync.Once from struct * Remove unnecessary struct element * Fix test * Disable XAttr testing in CI * Fix path joining in and test --delete-destination (#2620) * Automatically create the hash data directory when using an alternative * Fix path joining in and test --delete-destination * Create share test fix * Backport fixes from NewE2E early exit changes * Remove sync.Once struct from hidden file adapter * Prevent crash in blob * Use my braincells
1 parent d323e0b commit 8aec227

16 files changed

+396
-72
lines changed

cmd/syncProcessor.go

+48-48
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ func newSyncDeleteProcessor(cca *cookedSyncCmdArgs, fpo common.FolderPropertyOpt
247247
if err != nil {
248248
return nil, err
249249
}
250-
250+
251251
return newInteractiveDeleteProcessor(deleter.delete, cca.deleteDestination, cca.fromTo.To().String(), cca.destination, cca.incrementDeletionCount, cca.dryrunMode), nil
252252
}
253253

@@ -284,7 +284,7 @@ func (b *remoteResourceDeleter) getObjectURL(objectURL string) (*url.URL, error)
284284
if err != nil {
285285
return nil, err
286286
}
287-
return u,nil
287+
return u, nil
288288
}
289289

290290
func (b *remoteResourceDeleter) delete(object StoredObject) error {
@@ -305,12 +305,12 @@ func (b *remoteResourceDeleter) delete(object StoredObject) error {
305305

306306
var err error
307307
var objURL *url.URL
308-
308+
309309
switch b.targetLocation {
310310
case common.ELocation.Blob():
311311
bsc, _ := sc.BlobServiceClient()
312-
var blobClient *blob.Client = bsc.NewContainerClient(b.containerName).NewBlobClient(path.Join(b.rootPath + object.relativePath))
313-
312+
var blobClient *blob.Client = bsc.NewContainerClient(b.containerName).NewBlobClient(path.Join(b.rootPath, object.relativePath))
313+
314314
objURL, err = b.getObjectURL(blobClient.URL())
315315
if err != nil {
316316
break
@@ -321,7 +321,7 @@ func (b *remoteResourceDeleter) delete(object StoredObject) error {
321321
_, err = blobClient.Delete(b.ctx, nil)
322322
case common.ELocation.File():
323323
fsc, _ := sc.FileServiceClient()
324-
fileClient := fsc.NewShareClient(b.containerName).NewRootDirectoryClient().NewFileClient(path.Join(b.rootPath + object.relativePath))
324+
fileClient := fsc.NewShareClient(b.containerName).NewRootDirectoryClient().NewFileClient(path.Join(b.rootPath, object.relativePath))
325325

326326
objURL, err = b.getObjectURL(fileClient.URL())
327327
if err != nil {
@@ -330,13 +330,13 @@ func (b *remoteResourceDeleter) delete(object StoredObject) error {
330330
b.folderManager.RecordChildExists(objURL)
331331
defer b.folderManager.RecordChildDeleted(objURL)
332332

333-
err = common.DoWithOverrideReadOnlyOnAzureFiles(b.ctx, func()(interface{}, error) {
333+
err = common.DoWithOverrideReadOnlyOnAzureFiles(b.ctx, func() (interface{}, error) {
334334
return fileClient.Delete(b.ctx, nil)
335335
}, fileClient, b.forceIfReadOnly)
336336
case common.ELocation.BlobFS():
337337
dsc, _ := sc.DatalakeServiceClient()
338-
fileClient := dsc.NewFileSystemClient(b.containerName).NewFileClient(path.Join(b.rootPath + object.relativePath))
339-
338+
fileClient := dsc.NewFileSystemClient(b.containerName).NewFileClient(path.Join(b.rootPath, object.relativePath))
339+
340340
objURL, err = b.getObjectURL(fileClient.DFSURL())
341341
if err != nil {
342342
break
@@ -369,48 +369,48 @@ func (b *remoteResourceDeleter) delete(object StoredObject) error {
369369
var objURL *url.URL
370370
var err error
371371
switch b.targetLocation {
372-
case common.ELocation.Blob():
373-
bsc, _ := sc.BlobServiceClient()
374-
blobClient := bsc.NewContainerClient(b.containerName).NewBlobClient(path.Join(b.rootPath + object.relativePath))
375-
// HNS endpoint doesn't like delete snapshots on a directory
376-
objURL, err = b.getObjectURL(blobClient.URL())
377-
if err != nil {
378-
return err
379-
}
372+
case common.ELocation.Blob():
373+
bsc, _ := sc.BlobServiceClient()
374+
blobClient := bsc.NewContainerClient(b.containerName).NewBlobClient(path.Join(b.rootPath, object.relativePath))
375+
// HNS endpoint doesn't like delete snapshots on a directory
376+
objURL, err = b.getObjectURL(blobClient.URL())
377+
if err != nil {
378+
return err
379+
}
380380

381-
deleteFunc = func(ctx context.Context, logger common.ILogger) bool {
382-
_, err = blobClient.Delete(b.ctx, nil)
383-
return (err == nil)
384-
}
385-
case common.ELocation.File():
386-
fsc, _ := sc.FileServiceClient()
387-
dirClient := fsc.NewShareClient(b.containerName).NewDirectoryClient(path.Join(b.rootPath + object.relativePath))
388-
objURL, err = b.getObjectURL(dirClient.URL())
389-
if err != nil {
390-
return err
391-
}
381+
deleteFunc = func(ctx context.Context, logger common.ILogger) bool {
382+
_, err = blobClient.Delete(b.ctx, nil)
383+
return (err == nil)
384+
}
385+
case common.ELocation.File():
386+
fsc, _ := sc.FileServiceClient()
387+
dirClient := fsc.NewShareClient(b.containerName).NewDirectoryClient(path.Join(b.rootPath, object.relativePath))
388+
objURL, err = b.getObjectURL(dirClient.URL())
389+
if err != nil {
390+
return err
391+
}
392392

393-
deleteFunc = func(ctx context.Context, logger common.ILogger) bool {
394-
err = common.DoWithOverrideReadOnlyOnAzureFiles(b.ctx, func()(interface{}, error) {
395-
return dirClient.Delete(b.ctx, nil)
396-
}, dirClient, b.forceIfReadOnly)
397-
return (err == nil)
398-
}
399-
case common.ELocation.BlobFS():
400-
dsc, _ := sc.DatalakeServiceClient()
401-
directoryClient := dsc.NewFileSystemClient(b.containerName).NewDirectoryClient(path.Join(b.rootPath + object.relativePath))
402-
objURL, err = b.getObjectURL(directoryClient.DFSURL())
403-
if err != nil {
404-
return err
405-
}
393+
deleteFunc = func(ctx context.Context, logger common.ILogger) bool {
394+
err = common.DoWithOverrideReadOnlyOnAzureFiles(b.ctx, func() (interface{}, error) {
395+
return dirClient.Delete(b.ctx, nil)
396+
}, dirClient, b.forceIfReadOnly)
397+
return (err == nil)
398+
}
399+
case common.ELocation.BlobFS():
400+
dsc, _ := sc.DatalakeServiceClient()
401+
directoryClient := dsc.NewFileSystemClient(b.containerName).NewDirectoryClient(path.Join(b.rootPath, object.relativePath))
402+
objURL, err = b.getObjectURL(directoryClient.DFSURL())
403+
if err != nil {
404+
return err
405+
}
406406

407-
deleteFunc = func(ctx context.Context, logger common.ILogger) bool {
408-
recursiveContext := common.WithRecursive(b.ctx, false)
409-
_, err = directoryClient.Delete(recursiveContext, nil)
410-
return (err == nil)
411-
}
412-
default:
413-
panic("not implemented, check your code")
407+
deleteFunc = func(ctx context.Context, logger common.ILogger) bool {
408+
recursiveContext := common.WithRecursive(b.ctx, false)
409+
_, err = directoryClient.Delete(recursiveContext, nil)
410+
return (err == nil)
411+
}
412+
default:
413+
panic("not implemented, check your code")
414414
}
415415

416416
b.folderManager.RecordChildExists(objURL)

cmd/zt_make_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ func TestMakeFileShareQuota(t *testing.T) {
158158

159159
args := rawMakeCmdArgs{
160160
resourceToCreate: scSAS.String(),
161-
quota: 5,
161+
quota: 5,
162162
}
163163

164164
runMakeAndVerify(args, func(err error) {
@@ -191,4 +191,4 @@ func TestMakeFileShareExists(t *testing.T) {
191191
_, err = sc.GetProperties(ctx, nil)
192192
a.Nil(err)
193193
})
194-
}
194+
}

common/hash_data.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,21 @@ var LocalHashStorageMode = EHashStorageMode.Default()
2222
var LocalHashDir = ""
2323

2424
var hashDataFailureLogOnce = &sync.Once{}
25+
2526
func LogHashStorageFailure() {
2627
hashDataFailureLogOnce.Do(func() {
2728
lcm.Info("One or more hash storage operations (read/write) have failed. Check the scanning log for details.")
2829
})
2930
}
3031

3132
type HashStorageMode uint8
33+
3234
var EHashStorageMode = HashStorageMode(0)
3335

3436
func (HashStorageMode) HiddenFiles() HashStorageMode { return 0 }
3537

3638
func (e *HashStorageMode) Default() HashStorageMode {
37-
if defaulter, ok := any(e).(interface{osDefault() HashStorageMode}); ok { // allow specific OSes to override the default functionality
39+
if defaulter, ok := any(e).(interface{ osDefault() HashStorageMode }); ok { // allow specific OSes to override the default functionality
3840
return defaulter.osDefault()
3941
}
4042

common/hash_data_adapter_hidden_files.go

+8-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ type HiddenFileDataAdapter struct {
1414
}
1515

1616
func (a *HiddenFileDataAdapter) GetMode() HashStorageMode {
17-
return EHashStorageMode.Default()
17+
return EHashStorageMode.HiddenFiles()
1818
}
1919

2020
func (a *HiddenFileDataAdapter) getHashPath(relativePath string) string {
@@ -26,6 +26,12 @@ func (a *HiddenFileDataAdapter) getHashPath(relativePath string) string {
2626
dir, fName := filepath.Split(relativePath)
2727
fName = fmt.Sprintf(".%s%s", fName, AzCopyHashDataStream)
2828

29+
// Try to create the directory
30+
err := os.Mkdir(filepath.Join(basePath, dir), 0775)
31+
if err != nil && !os.IsExist(err) {
32+
lcm.Warn("Failed to create hash data directory")
33+
}
34+
2935
return filepath.Join(basePath, dir, fName)
3036
}
3137

@@ -76,7 +82,7 @@ func (a *HiddenFileDataAdapter) SetHashData(relativePath string, data *SyncHashD
7682
}
7783

7884
// Push types around to check for OS-specific hide file method
79-
if adapter, canHide := any(a).(interface{HideFile(string) error}); canHide {
85+
if adapter, canHide := any(a).(interface{ HideFile(string) error }); canHide {
8086
dataFile := a.getDataPath(relativePath)
8187

8288
err := adapter.HideFile(dataFile)

e2etest/newe2e_asserter.go

+47-5
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@ import (
66
"testing"
77
)
88

9+
var _ Asserter = &FrameworkAsserter{}
10+
var _ ScenarioAsserter = &ScenarioVariationManager{} // covers all 3 interfaces
11+
912
// ====== Asserter ======
1013

1114
type Asserter interface {
12-
NoError(comment string, err error)
15+
NoError(comment string, err error, failNow ...bool)
1316
// Assert fails the test, but does not exit.
1417
Assert(comment string, assertion Assertion, items ...any)
1518
// AssertNow wraps Assert, and exits if failed.
@@ -23,6 +26,8 @@ type Asserter interface {
2326

2427
// Failed returns if the test has already failed.
2528
Failed() bool
29+
// HelperMarker returns the associated *testing.T, and if there is none, a NilHelperMarker.
30+
HelperMarker() HelperMarker
2631
}
2732

2833
type DryrunAsserter interface {
@@ -39,6 +44,15 @@ type ScenarioAsserter interface {
3944
Cleanup(func(a ScenarioAsserter))
4045
}
4146

47+
// HelperMarker handles the fact that testing.T can be sometimes nil, and that we can't indicate a depth to ignore with Helper()
48+
type HelperMarker interface {
49+
Helper()
50+
}
51+
52+
type NilHelperMarker struct{}
53+
54+
func (NilHelperMarker) Helper() {}
55+
4256
// ====== Assertion ======
4357

4458
type Assertion interface {
@@ -118,15 +132,35 @@ func (ta *FrameworkAsserter) Log(format string, a ...any) {
118132
ta.t.Log(fmt.Sprintf(format, a...))
119133
}
120134

121-
func (ta *FrameworkAsserter) NoError(comment string, err error) {
135+
func (ta *FrameworkAsserter) NoError(comment string, err error, failNow ...bool) {
122136
ta.t.Helper()
123-
ta.AssertNow(comment, IsNil{}, err)
137+
138+
if err != nil {
139+
ta.t.Logf("Error was not nil (%s): %v", comment, err)
140+
141+
if FirstOrZero(failNow) {
142+
ta.t.FailNow()
143+
} else {
144+
ta.t.Fail()
145+
}
146+
}
124147
}
125148

126149
func (ta *FrameworkAsserter) AssertNow(comment string, assertion Assertion, items ...any) {
127150
ta.t.Helper()
128-
ta.Assert(comment, assertion, items...)
129-
if ta.Failed() {
151+
152+
if (assertion.MinArgs() > 0 && len(items) < assertion.MinArgs()) || (assertion.MaxArgs() > 0 && len(items) > assertion.MaxArgs()) {
153+
ta.PrintFinalizingMessage("Failed to assert: Assertion %s supports argument counts between %d and %d, but received %d args.", assertion.Name(), assertion.MinArgs(), assertion.MaxArgs(), len(items))
154+
ta.t.FailNow()
155+
}
156+
157+
if !assertion.Assert(items...) {
158+
if fa, ok := assertion.(FormattedAssertion); ok {
159+
ta.PrintFinalizingMessage("Failed assertion %s: %s; %s", fa.Name(), fa.Format(items...), comment)
160+
} else {
161+
ta.PrintFinalizingMessage("Failed assertion %s with item(s): %v; %s", assertion.Name(), items, comment)
162+
}
163+
130164
ta.t.FailNow()
131165
}
132166
}
@@ -165,3 +199,11 @@ func (ta *FrameworkAsserter) Failed() bool {
165199
ta.t.Helper()
166200
return ta.t.Failed()
167201
}
202+
203+
func (ta *FrameworkAsserter) HelperMarker() HelperMarker {
204+
if ta.t != nil {
205+
return ta.t
206+
}
207+
208+
return NilHelperMarker{}
209+
}

e2etest/newe2e_object_content.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package e2etest
22

33
import (
44
"bytes"
5+
"crypto/md5"
56
"github.com/Azure/azure-storage-azcopy/v10/cmd"
67
"github.com/Azure/azure-storage-azcopy/v10/common"
78
"io"
@@ -11,7 +12,7 @@ import (
1112
type ObjectContentContainer interface {
1213
Size() int64
1314
Reader() io.ReadSeeker
14-
//MD5() [md5.Size]byte
15+
MD5() [md5.Size]byte
1516
//CRC64() uint64
1617
}
1718

@@ -48,3 +49,7 @@ func (o *ObjectContentContainerBuffer) Size() int64 {
4849
func (o *ObjectContentContainerBuffer) Reader() io.ReadSeeker {
4950
return bytes.NewReader(o.Data)
5051
}
52+
53+
func (o *ObjectContentContainerBuffer) MD5() [md5.Size]byte {
54+
return md5.Sum(o.Data)
55+
}

e2etest/newe2e_resource_manager_interface.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,9 @@ type ObjectResourceManager interface {
239239
EntityType() common.EntityType
240240
ContainerName() string
241241
ObjectName() string
242-
// Create attempts to create an object. Should overwrite objects if they already exist. It is expected to attempt to track object creation.
242+
// Create attempts to create an object. Should overwrite objects if they already exist.
243+
// It is expected to attempt to track object creation.
244+
// It is also expected to create parents, if required.
243245
Create(a Asserter, body ObjectContentContainer, properties ObjectProperties)
244246
// Delete attempts to delete an object. NotFound type errors are ignored.
245247
Delete(a Asserter)

e2etest/newe2e_resource_managers_blob.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -684,8 +684,10 @@ func (b *BlobObjectResourceManager) Download(a Asserter) io.ReadSeeker {
684684
a.NoError("Download stream", err)
685685

686686
buf := &bytes.Buffer{}
687-
_, err = io.Copy(buf, resp.Body)
688-
a.NoError("Read body", err)
687+
if err == nil && resp.Body != nil {
688+
_, err = io.Copy(buf, resp.Body)
689+
a.NoError("Read body", err)
690+
}
689691

690692
return bytes.NewReader(buf.Bytes())
691693
}

0 commit comments

Comments
 (0)