Skip to content

Commit 7cecb73

Browse files
Improved some logging messages and --log-level NONE behavior (#2845)
1 parent 74ff288 commit 7cecb73

16 files changed

+171
-35
lines changed

cmd/copy.go

+14-7
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,11 @@ func (raw rawCopyCmdArgs) cook() (CookedCopyCmdArgs, error) {
279279
azcopyScanningLogger.CloseLog()
280280
})
281281

282+
// if no logging, set this empty so that we don't display the log location
283+
if azcopyLogVerbosity == common.LogNone {
284+
azcopyLogPathFolder = ""
285+
}
286+
282287
fromTo, err := ValidateFromTo(raw.src, raw.dst, raw.fromTo) // TODO: src/dst
283288
if err != nil {
284289
return cooked, err
@@ -549,7 +554,7 @@ func (raw rawCopyCmdArgs) cook() (CookedCopyCmdArgs, error) {
549554
}
550555

551556
if cooked.FromTo.To() == common.ELocation.None() && strings.EqualFold(raw.metadata, common.MetadataAndBlobTagsClearFlag) { // in case of Blob, BlobFS and Files
552-
glcm.Info("*** WARNING *** Metadata will be cleared because of input --metadata=clear ")
557+
glcm.Warn("*** WARNING *** Metadata will be cleared because of input --metadata=clear ")
553558
}
554559
cooked.metadata = raw.metadata
555560
if err = validateMetadataString(cooked.metadata); err != nil {
@@ -573,7 +578,7 @@ func (raw rawCopyCmdArgs) cook() (CookedCopyCmdArgs, error) {
573578
return cooked, errors.New("blob tags can only be set when transferring to blob storage")
574579
}
575580
if cooked.FromTo.To() == common.ELocation.None() && strings.EqualFold(raw.blobTags, common.MetadataAndBlobTagsClearFlag) { // in case of Blob and BlobFS
576-
glcm.Info("*** WARNING *** BlobTags will be cleared because of input --blob-tags=clear ")
581+
glcm.Warn("*** WARNING *** BlobTags will be cleared because of input --blob-tags=clear ")
577582
}
578583
blobTags := common.ToCommonBlobTagsMap(raw.blobTags)
579584
err = validateBlobTagsKeyValue(blobTags)
@@ -901,7 +906,7 @@ var includeWarningOncer = &sync.Once{}
901906
func (raw *rawCopyCmdArgs) warnIfHasWildcard(oncer *sync.Once, paramName string, value string) {
902907
if strings.Contains(value, "*") || strings.Contains(value, "?") {
903908
oncer.Do(func() {
904-
glcm.Info(fmt.Sprintf("*** Warning *** The %s parameter does not support wildcards. The wildcard "+
909+
glcm.Warn(fmt.Sprintf("*** Warning *** The %s parameter does not support wildcards. The wildcard "+
905910
"character provided will be interpreted literally and will not have any wildcard effect. To use wildcards "+
906911
"(in filenames only, not paths) use include-pattern or exclude-pattern", paramName))
907912
})
@@ -1689,11 +1694,13 @@ func (cca *CookedCopyCmdArgs) waitUntilJobCompletion(blocking bool) {
16891694
// print initial message to indicate that the job is starting
16901695
// if on dry run mode do not want to print message since no job is being done
16911696
if !cca.dryrunMode {
1697+
// Output the log location if log-level is set to other then NONE
1698+
var logPathFolder string
1699+
if azcopyLogPathFolder != "" {
1700+
logPathFolder = fmt.Sprintf("%s%s%s.log", azcopyLogPathFolder, common.OS_PATH_SEPARATOR, cca.jobID)
1701+
}
16921702
glcm.Init(common.GetStandardInitOutputBuilder(cca.jobID.String(),
1693-
fmt.Sprintf("%s%s%s.log",
1694-
azcopyLogPathFolder,
1695-
common.OS_PATH_SEPARATOR,
1696-
cca.jobID),
1703+
logPathFolder,
16971704
cca.isCleanupJob,
16981705
cca.cleanupJobMessage))
16991706
}

cmd/copyEnumeratorHelper.go

+9-4
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,18 @@ package cmd
22

33
import (
44
"fmt"
5+
"math/rand"
6+
57
"github.com/Azure/azure-storage-azcopy/v10/common"
68
"github.com/Azure/azure-storage-azcopy/v10/jobsAdmin"
7-
"math/rand"
89
)
910

1011
var EnumerationParallelism = 1
1112
var EnumerationParallelStatFiles = false
1213

1314
// addTransfer accepts a new transfer, if the threshold is reached, dispatch a job part order.
1415
func addTransfer(e *common.CopyJobPartOrderRequest, transfer common.CopyTransfer, cca *CookedCopyCmdArgs) error {
15-
// Source and destination paths are and should be relative paths.
16+
// Source and destination paths are and should be relative paths.
1617

1718
// dispatch the transfers once the number reaches NumOfFilesPerDispatchJobPart
1819
// we do this so that in the case of large transfer, the transfer engine can get started
@@ -69,8 +70,12 @@ func dispatchFinalPart(e *common.CopyJobPartOrderRequest, cca *CookedCopyCmdArgs
6970
Rpc(common.ERpcCmd.CopyJobPartOrder(), (*common.CopyJobPartOrderRequest)(e), &resp)
7071

7172
if !resp.JobStarted {
72-
// Output the log location and such
73-
glcm.Init(common.GetStandardInitOutputBuilder(cca.jobID.String(), fmt.Sprintf("%s%s%s.log", azcopyLogPathFolder, common.OS_PATH_SEPARATOR, cca.jobID), cca.isCleanupJob, cca.cleanupJobMessage))
73+
// Output the log location if log-level is set to other then NONE
74+
var logPathFolder string
75+
if azcopyLogPathFolder != "" {
76+
logPathFolder = fmt.Sprintf("%s%s%s.log", azcopyLogPathFolder, common.OS_PATH_SEPARATOR, cca.jobID)
77+
}
78+
glcm.Init(common.GetStandardInitOutputBuilder(cca.jobID.String(), logPathFolder, cca.isCleanupJob, cca.cleanupJobMessage))
7479

7580
if cca.dryrunMode {
7681
return nil

cmd/copyEnumeratorInit.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ func (cca *CookedCopyCmdArgs) initEnumerator(jobPartOrder common.CopyJobPartOrde
157157
// check against seenFailedContainers so we don't spam the job log with initialization failed errors
158158
if _, ok := seenFailedContainers[dstContainerName]; err != nil && jobsAdmin.JobsAdmin != nil && !ok {
159159
logDstContainerCreateFailureOnce.Do(func() {
160-
glcm.Info("Failed to create one or more destination container(s). Your transfers may still succeed if the container already exists.")
160+
glcm.Warn("Failed to create one or more destination container(s). Your transfers may still succeed if the container already exists.")
161161
})
162162
jobsAdmin.JobsAdmin.LogToJobLog(fmt.Sprintf("Failed to create destination container %s. The transfer will continue if the container exists", dstContainerName), common.LogWarning)
163163
jobsAdmin.JobsAdmin.LogToJobLog(fmt.Sprintf("Error %s", err), common.LogDebug)
@@ -194,7 +194,7 @@ func (cca *CookedCopyCmdArgs) initEnumerator(jobPartOrder common.CopyJobPartOrde
194194
// check against seenFailedContainers so we don't spam the job log with initialization failed errors
195195
if _, ok := seenFailedContainers[bucketName]; err != nil && jobsAdmin.JobsAdmin != nil && !ok {
196196
logDstContainerCreateFailureOnce.Do(func() {
197-
glcm.Info("Failed to create one or more destination container(s). Your transfers may still succeed if the container already exists.")
197+
glcm.Warn("Failed to create one or more destination container(s). Your transfers may still succeed if the container already exists.")
198198
})
199199
jobsAdmin.JobsAdmin.LogToJobLog(fmt.Sprintf("failed to initialize destination container %s; the transfer will continue (but be wary it may fail).", bucketName), common.LogWarning)
200200
jobsAdmin.JobsAdmin.LogToJobLog(fmt.Sprintf("Error %s", err), common.LogDebug)
@@ -215,7 +215,7 @@ func (cca *CookedCopyCmdArgs) initEnumerator(jobPartOrder common.CopyJobPartOrde
215215

216216
if _, ok := seenFailedContainers[dstContainerName]; err != nil && jobsAdmin.JobsAdmin != nil && !ok {
217217
logDstContainerCreateFailureOnce.Do(func() {
218-
glcm.Info("Failed to create one or more destination container(s). Your transfers may still succeed if the container already exists.")
218+
glcm.Warn("Failed to create one or more destination container(s). Your transfers may still succeed if the container already exists.")
219219
})
220220
jobsAdmin.JobsAdmin.LogToJobLog(fmt.Sprintf("failed to initialize destination container %s; the transfer will continue (but be wary it may fail).", resName), common.LogWarning)
221221
jobsAdmin.JobsAdmin.LogToJobLog(fmt.Sprintf("Error %s", err), common.LogDebug)

cmd/jobsResume.go

+11-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,12 @@ type resumeJobController struct {
5959
// if blocking is specified to false, then another goroutine spawns and wait out the job
6060
func (cca *resumeJobController) waitUntilJobCompletion(blocking bool) {
6161
// print initial message to indicate that the job is starting
62-
glcm.Init(common.GetStandardInitOutputBuilder(cca.jobID.String(), fmt.Sprintf("%s%s%s.log", azcopyLogPathFolder, common.OS_PATH_SEPARATOR, cca.jobID), false, ""))
62+
// Output the log location if log-level is set to other then NONE
63+
var logPathFolder string
64+
if azcopyLogPathFolder != "" {
65+
logPathFolder = fmt.Sprintf("%s%s%s.log", azcopyLogPathFolder, common.OS_PATH_SEPARATOR, cca.jobID)
66+
}
67+
glcm.Init(common.GetStandardInitOutputBuilder(cca.jobID.String(), logPathFolder, false, ""))
6368

6469
// initialize the times necessary to track progress
6570
cca.jobStartTime = time.Now()
@@ -350,6 +355,11 @@ func (rca resumeCmdArgs) process() error {
350355
return fmt.Errorf("error parsing the jobId %s. Failed with error %s", rca.jobID, err.Error())
351356
}
352357

358+
// if no logging, set this empty so that we don't display the log location
359+
if azcopyLogVerbosity == common.LogNone {
360+
azcopyLogPathFolder = ""
361+
}
362+
353363
includeTransfer := make(map[string]int)
354364
excludeTransfer := make(map[string]int)
355365

cmd/root.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ func init() {
255255
rootCmd.PersistentFlags().Float64Var(&cmdLineCapMegaBitsPerSecond, "cap-mbps", 0, "Caps the transfer rate, in megabits per second. Moment-by-moment throughput might vary slightly from the cap. If this option is set to zero, or it is omitted, the throughput isn't capped.")
256256
rootCmd.PersistentFlags().StringVar(&outputFormatRaw, "output-type", "text", "Format of the command's output. The choices include: text, json. The default value is 'text'.")
257257
rootCmd.PersistentFlags().StringVar(&outputVerbosityRaw, "output-level", "default", "Define the output verbosity. Available levels: essential, quiet.")
258-
rootCmd.PersistentFlags().StringVar(&logVerbosityRaw, "log-level", "INFO", "Define the log verbosity for the log file, available levels: INFO(all requests/responses), WARNING(slow responses), ERROR(only failed requests), and NONE(no output logs). (default 'INFO').")
258+
rootCmd.PersistentFlags().StringVar(&logVerbosityRaw, "log-level", "INFO", "Define the log verbosity for the log file, available levels: DEBUG(detailed trace), INFO(all requests/responses), WARNING(slow responses), ERROR(only failed requests), and NONE(no output logs). (default 'INFO').")
259259

260260
rootCmd.PersistentFlags().StringVar(&cmdLineExtraSuffixesAAD, trustedSuffixesNameAAD, "", "Specifies additional domain suffixes where Azure Active Directory login tokens may be sent. The default is '"+
261261
trustedSuffixesAAD+"'. Any listed here are added to the default. For security, you should only put Microsoft Azure domains here. Separate multiple entries with semi-colons.")

cmd/sync.go

+11-1
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,11 @@ func (raw *rawSyncCmdArgs) cook() (cookedSyncCmdArgs, error) {
140140
azcopyScanningLogger.CloseLog()
141141
})
142142

143+
// if no logging, set this empty so that we don't display the log location
144+
if azcopyLogVerbosity == common.LogNone {
145+
azcopyLogPathFolder = ""
146+
}
147+
143148
// this if statement ladder remains instead of being separated to help determine valid combinations for sync
144149
// consider making a map of valid source/dest combos and consolidating this to generic source/dest setups, akin to the lower if statement
145150
// TODO: if expand the set of source/dest combos supported by sync, update this method the declarative test framework:
@@ -505,7 +510,12 @@ func (cca *cookedSyncCmdArgs) scanningComplete() bool {
505510
// if blocking is specified to false, then another goroutine spawns and wait out the job
506511
func (cca *cookedSyncCmdArgs) waitUntilJobCompletion(blocking bool) {
507512
// print initial message to indicate that the job is starting
508-
glcm.Init(common.GetStandardInitOutputBuilder(cca.jobID.String(), fmt.Sprintf("%s%s%s.log", azcopyLogPathFolder, common.OS_PATH_SEPARATOR, cca.jobID), false, ""))
513+
// Output the log location if log-level is set to other then NONE
514+
var logPathFolder string
515+
if azcopyLogPathFolder != "" {
516+
logPathFolder = fmt.Sprintf("%s%s%s.log", azcopyLogPathFolder, common.OS_PATH_SEPARATOR, cca.jobID)
517+
}
518+
glcm.Init(common.GetStandardInitOutputBuilder(cca.jobID.String(), logPathFolder, false, ""))
509519

510520
// initialize the times necessary to track progress
511521
cca.jobStartTime = time.Now()

common/output.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,9 @@ func GetStandardInitOutputBuilder(jobID string, logFileLocation string, isCleanu
118118
sb.WriteString(cleanupHeader)
119119
} else {
120120
sb.WriteString("\nJob " + jobID + " has started\n")
121-
sb.WriteString("Log file is located at: " + logFileLocation)
121+
if logFileLocation != "" {
122+
sb.WriteString("Log file is located at: " + logFileLocation)
123+
}
122124
sb.WriteString("\n")
123125
}
124126
return sb.String()

e2etest/newe2e_task_validation.go

+7-2
Original file line numberDiff line numberDiff line change
@@ -175,15 +175,20 @@ func ValidateListOutput(a Asserter, stdout AzCopyStdout, expectedObjects map[AzC
175175
a.Assert("summary must match", Equal{}, listStdout.Summary, DerefOrZero(expectedSummary))
176176
}
177177

178-
func ValidateMessageOutput(a Asserter, stdout AzCopyStdout, message string) {
178+
func ValidateMessageOutput(a Asserter, stdout AzCopyStdout, message string, shouldContain bool) {
179179
if dryrunner, ok := a.(DryrunAsserter); ok && dryrunner.Dryrun() {
180180
return
181181
}
182+
var contains bool
182183
for _, line := range stdout.RawStdout() {
183184
if strings.Contains(line, message) {
184-
return
185+
contains = true
186+
break
185187
}
186188
}
189+
if (!contains && !shouldContain) || (contains && shouldContain) {
190+
return
191+
}
187192
fmt.Println(stdout.String())
188193
a.Error(fmt.Sprintf("expected message (%s) not found in azcopy output", message))
189194
}

e2etest/zt_azcopy_flags_test.go

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// Copyright © Microsoft <[email protected]>
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a copy
4+
// of this software and associated documentation files (the "Software"), to deal
5+
// in the Software without restriction, including without limitation the rights
6+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
// copies of the Software, and to permit persons to whom the Software is
8+
// furnished to do so, subject to the following conditions:
9+
//
10+
// The above copyright notice and this permission notice shall be included in
11+
// all copies or substantial portions of the Software.
12+
//
13+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
// THE SOFTWARE.
20+
21+
package e2etest
22+
23+
import (
24+
"time"
25+
26+
"github.com/Azure/azure-storage-azcopy/v10/common"
27+
)
28+
29+
func init() {
30+
suiteManager.RegisterSuite(&FlagsFunctionalitySuite{})
31+
}
32+
33+
type FlagsFunctionalitySuite struct{}
34+
35+
// @brief This test verifies that when the --log-level is set to NONE,
36+
// AzCopy does not display the "Log files located" message on the console.
37+
func (s *FlagsFunctionalitySuite) Scenario_LogLevelNone(svm *ScenarioVariationManager) {
38+
azCopyVerb := ResolveVariation(svm, []AzCopyVerb{AzCopyVerbCopy, AzCopyVerbSync}) // Calculate verb early to create the destination object early
39+
// Scale up from service to object
40+
dstObj := CreateResource[ContainerResourceManager](svm, GetRootResource(svm, ResolveVariation(svm, []common.Location{common.ELocation.Local(), common.ELocation.Blob(), common.ELocation.File(), common.ELocation.BlobFS()})), ResourceDefinitionContainer{}).GetObject(svm, "test", common.EEntityType.File())
41+
42+
// The object must exist already if we're syncing.
43+
if azCopyVerb == AzCopyVerbSync {
44+
dstObj.Create(svm, NewZeroObjectContentContainer(0), ObjectProperties{})
45+
46+
if !svm.Dryrun() {
47+
// Make sure the LMT is in the past
48+
time.Sleep(time.Second * 10)
49+
}
50+
}
51+
52+
body := NewRandomObjectContentContainer(SizeFromString("10K"))
53+
// Scale up from service to object
54+
srcObj := CreateResource[ObjectResourceManager](svm, GetRootResource(svm, ResolveVariation(svm, []common.Location{ /*common.ELocation.Local(), */ common.ELocation.Blob() /*, common.ELocation.File(), common.ELocation.BlobFS()*/})), ResourceDefinitionObject{
55+
ObjectName: pointerTo("test"),
56+
Body: body,
57+
})
58+
59+
// no local->local
60+
if srcObj.Location().IsLocal() && dstObj.Location().IsLocal() {
61+
svm.InvalidateScenario()
62+
return
63+
}
64+
65+
sasOpts := GenericAccountSignatureValues{}
66+
logLevel := common.LogLevel.None(common.LogNone)
67+
outputType := common.EOutputFormat.Text()
68+
69+
stdOut, _ := RunAzCopy(
70+
svm,
71+
AzCopyCommand{
72+
Verb: azCopyVerb,
73+
Targets: []ResourceManager{
74+
TryApplySpecificAuthType(srcObj, EExplicitCredentialType.SASToken(), svm, CreateAzCopyTargetOptions{
75+
SASTokenOptions: sasOpts,
76+
}),
77+
TryApplySpecificAuthType(dstObj, EExplicitCredentialType.SASToken(), svm, CreateAzCopyTargetOptions{
78+
SASTokenOptions: sasOpts,
79+
}),
80+
},
81+
Flags: CopyFlags{
82+
CopySyncCommonFlags: CopySyncCommonFlags{
83+
Recursive: pointerTo(true),
84+
GlobalFlags: GlobalFlags{
85+
LogLevel: &logLevel,
86+
OutputType: &outputType,
87+
},
88+
},
89+
},
90+
})
91+
ValidateMessageOutput(svm, stdOut, "Log file is located at", false)
92+
}

e2etest/zt_newe2e_basic_functionality_test.go

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
package e2etest
22

33
import (
4+
"strconv"
5+
"time"
6+
47
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
58
blobsas "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/sas"
69
"github.com/Azure/azure-storage-azcopy/v10/common"
7-
"strconv"
8-
"time"
910
)
1011

1112
func init() {
@@ -347,7 +348,7 @@ func (s *BasicFunctionalitySuite) Scenario_SingleFileUploadDownload_EmptySAS(svm
347348
})
348349

349350
// Validate that the stdout contains the missing sas message
350-
ValidateMessageOutput(svm, stdout, "Please authenticate using Microsoft Entra ID (https://aka.ms/AzCopy/AuthZ), use AzCopy login, or append a SAS token to your Azure URL.")
351+
ValidateMessageOutput(svm, stdout, "Please authenticate using Microsoft Entra ID (https://aka.ms/AzCopy/AuthZ), use AzCopy login, or append a SAS token to your Azure URL.", true)
351352
}
352353

353354
func (s *BasicFunctionalitySuite) Scenario_Sync_EmptySASErrorCodes(svm *ScenarioVariationManager) {
@@ -534,5 +535,5 @@ func (s *BasicFunctionalitySuite) Scenario_TagsPermission(svm *ScenarioVariation
534535
},
535536
)
536537

537-
ValidateMessageOutput(svm, stdOut, "Authorization failed during an attempt to set tags, please ensure you have the appropriate Tags permission")
538+
ValidateMessageOutput(svm, stdOut, "Authorization failed during an attempt to set tags, please ensure you have the appropriate Tags permission", true)
538539
}

e2etest/zt_newe2e_file_oauth_test.go

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

33
import (
44
"fmt"
5+
56
"github.com/Azure/azure-storage-azcopy/v10/common"
67
)
78

@@ -35,5 +36,5 @@ func (s *FileOAuthTestSuite) Scenario_FileBlobOAuthError(svm *ScenarioVariationM
3536
ShouldFail: true,
3637
})
3738

38-
ValidateMessageOutput(svm, stdout, fmt.Sprintf("S2S %s from Azure File authenticated with Azure AD to Blob/BlobFS is not supported", azCopyVerb))
39+
ValidateMessageOutput(svm, stdout, fmt.Sprintf("S2S %s from Azure File authenticated with Azure AD to Blob/BlobFS is not supported", azCopyVerb), true)
3940
}

e2etest/zt_newe2e_jobs_clean_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,5 +43,5 @@ func (s *JobsCleanSuite) Scenario_JobsCleanBasic(svm *ScenarioVariationManager)
4343
},
4444
})
4545

46-
ValidateMessageOutput(svm, jobsCleanOutput, cmd.JobsCleanupSuccessMsg)
46+
ValidateMessageOutput(svm, jobsCleanOutput, cmd.JobsCleanupSuccessMsg, true)
4747
}

e2etest/zt_newe2e_list_test.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
package e2etest
22

33
import (
4+
"strings"
5+
46
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
57
blobsas "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/sas"
68
"github.com/Azure/azure-storage-azcopy/v10/cmd"
79
"github.com/Azure/azure-storage-azcopy/v10/common"
8-
"strings"
910
)
1011

1112
func init() {
@@ -820,7 +821,7 @@ func (s *ListSuite) Scenario_EmptySASErrorCodes(svm *ScenarioVariationManager) {
820821
})
821822

822823
// Validate that the stdout contains these error URLs
823-
ValidateMessageOutput(svm, stdout, "https://aka.ms/AzCopyError/NoAuthenticationInformation")
824+
ValidateMessageOutput(svm, stdout, "https://aka.ms/AzCopyError/NoAuthenticationInformation", true)
824825
}
825826

826827
func (s *ListSuite) Scenario_VirtualDirectoryHandling(svm *ScenarioVariationManager) {

0 commit comments

Comments
 (0)