@@ -70,6 +70,31 @@ type scenarioState struct {
70
70
func (s * scenario ) Run () {
71
71
defer s .cleanup ()
72
72
73
+ // setup runner
74
+ azcopyDir , err := os .MkdirTemp ("" , "" )
75
+ if err != nil {
76
+ s .a .Error (err .Error ())
77
+ return
78
+ }
79
+ azcopyRan := false
80
+ defer func () {
81
+ if os .Getenv ("AZCOPY_E2E_LOG_OUTPUT" ) == "" {
82
+ s .a .Assert (os .RemoveAll (azcopyDir ), equals (), nil )
83
+ return // no need, just delete logdir
84
+ }
85
+
86
+ err := os .MkdirAll (os .Getenv ("AZCOPY_E2E_LOG_OUTPUT" ), os .ModePerm | os .ModeDir )
87
+ if err != nil {
88
+ s .a .Assert (err , equals (), nil )
89
+ return
90
+ }
91
+ if azcopyRan && s .a .Failed () {
92
+ s .uploadLogs (azcopyDir )
93
+ s .a .(* testingAsserter ).t .Log ("uploaded logs for job " + s .state .result .jobID .String () + " as an artifact" )
94
+ }
95
+ }()
96
+
97
+ // setup scenario
73
98
// First, validate the accounts make sense for the source/dests
74
99
if s .srcAccountType .IsBlobOnly () {
75
100
s .a .Assert (s .fromTo .From (), equals (), common .ELocation .Blob ())
@@ -97,29 +122,30 @@ func (s *scenario) Run() {
97
122
}
98
123
99
124
// execute
100
- s .runAzCopy ()
125
+ azcopyRan = true
126
+ s .runAzCopy (azcopyDir )
101
127
if s .a .Failed () {
102
128
return // execution failed. No point in running validation
103
129
}
104
130
105
131
// resume if needed
106
132
if s .needResume {
107
- tx , err := s .state .result .GetTransferList (common .ETransferStatus .Cancelled ())
133
+ tx , err := s .state .result .GetTransferList (common .ETransferStatus .Cancelled (), azcopyDir )
108
134
s .a .AssertNoErr (err , "Failed to get transfer list for Cancelled" )
109
135
s .a .Assert (len (tx ), equals (), len (s .p .debugSkipFiles ), "Job cancel didn't completely work" )
110
136
111
137
if ! s .runHook (s .hs .beforeResumeHook ) {
112
138
return
113
139
}
114
140
115
- s .resumeAzCopy ()
141
+ s .resumeAzCopy (azcopyDir )
116
142
}
117
143
if s .a .Failed () {
118
144
return // resume failed. No point in running validation
119
145
}
120
146
121
147
// check
122
- s .validateTransferStates ()
148
+ s .validateTransferStates (azcopyDir )
123
149
if s .a .Failed () {
124
150
return // no point in doing more validation
125
151
}
@@ -138,6 +164,13 @@ func (s *scenario) Run() {
138
164
s .runHook (s .hs .afterValidation )
139
165
}
140
166
167
+ func (s * scenario ) uploadLogs (logDir string ) {
168
+ if s .state .result == nil || os .Getenv ("AZCOPY_E2E_LOG_OUTPUT" ) == "" {
169
+ return // nothing to upload
170
+ }
171
+ s .a .Assert (os .Rename (logDir , filepath .Join (os .Getenv ("AZCOPY_E2E_LOG_OUTPUT" ), s .state .result .jobID .String ())), equals (), nil )
172
+ }
173
+
141
174
func (s * scenario ) runHook (h hookFunc ) bool {
142
175
if h == nil {
143
176
return true // nothing to do. So "successful"
@@ -195,7 +228,7 @@ func (s *scenario) assignSourceAndDest() {
195
228
s .state .dest = createTestResource (s .fromTo .To (), false )
196
229
}
197
230
198
- func (s * scenario ) runAzCopy () {
231
+ func (s * scenario ) runAzCopy (logDirectory string ) {
199
232
s .chToStdin = make (chan string ) // unubuffered seems the most predictable for our usages
200
233
defer close (s .chToStdin )
201
234
@@ -223,9 +256,9 @@ func (s *scenario) runAzCopy() {
223
256
result , wasClean , err := r .ExecuteAzCopyCommand (
224
257
s .operation ,
225
258
s .state .source .getParam (s .stripTopDir , needsSAS (s .credTypes [0 ]), tf .objectTarget ),
226
- s .state .dest .getParam (false , needsSAS (s .credTypes [1 ]), common .IffString (tf .destTarget != "" , tf .destTarget , tf .objectTarget )),
227
- s .credTypes [0 ]. IsAzureOAuth () || s .credTypes [1 ]. IsAzureOAuth (), // needsOAuth
228
- afterStart , s .chToStdin )
259
+ s .state .dest .getParam (false , needsSAS (s .credTypes [1 ]), common .IffString (tf .destTarget != "" , tf .destTarget , tf .objectTarget )),
260
+ s .credTypes [0 ] == common . ECredentialType . OAuthToken () || s .credTypes [1 ] == common . ECredentialType . OAuthToken (), // needsOAuth
261
+ afterStart , s .chToStdin , logDirectory )
229
262
230
263
if ! wasClean {
231
264
s .a .AssertNoErr (err , "running AzCopy" )
@@ -243,7 +276,7 @@ func (s *scenario) runAzCopy() {
243
276
s .state .result = & result
244
277
}
245
278
246
- func (s * scenario ) resumeAzCopy () {
279
+ func (s * scenario ) resumeAzCopy (logDir string ) {
247
280
s .chToStdin = make (chan string ) // unubuffered seems the most predictable for our usages
248
281
defer close (s .chToStdin )
249
282
@@ -274,6 +307,7 @@ func (s *scenario) resumeAzCopy() {
274
307
false ,
275
308
afterStart ,
276
309
s .chToStdin ,
310
+ logDir ,
277
311
)
278
312
279
313
if ! wasClean {
@@ -295,7 +329,7 @@ func (s *scenario) validateRemove() {
295
329
}
296
330
}
297
331
}
298
- func (s * scenario ) validateTransferStates () {
332
+ func (s * scenario ) validateTransferStates (azcopyDir string ) {
299
333
if s .operation == eOperation .Remove () {
300
334
s .validateRemove ()
301
335
return
@@ -318,7 +352,7 @@ func (s *scenario) validateTransferStates() {
318
352
// Is that OK? (Not sure what to do if it's not, because azcopy jobs show, apparently doesn't offer us a way to get the skipped list)
319
353
} {
320
354
expectedTransfers := s .fs .getForStatus (statusToTest , expectFolders , expectRootFolder )
321
- actualTransfers , err := s .state .result .GetTransferList (statusToTest )
355
+ actualTransfers , err := s .state .result .GetTransferList (statusToTest , azcopyDir )
322
356
s .a .AssertNoErr (err )
323
357
324
358
Validator {}.ValidateCopyTransfersAreScheduled (s .a , isSrcEncoded , isDstEncoded , srcRoot , dstRoot , expectedTransfers , actualTransfers , statusToTest , s .FromTo (), s .srcAccountType , s .destAccountType )
0 commit comments