in e2etest/declarativeRunner.go [107:236]
func RunScenarios(
t *testing.T,
operations Operation,
testFromTo TestFromTo,
validate Validate, // TODO: do we really want the test author to have to nominate which validation should happen? Pros: better perf of tests. Cons: they have to tell us, and if they tell us wrong test may not test what they think it tests
// _ interface{}, // TODO if we want it??, blockBlobsOnly or specific/all blob types
// It would be a pain to list out every combo by hand,
// In addition to the fact that not every credential type is sensible.
// Thus, the E2E framework takes in a requested set of credential types, and applies them where sensible.
// This allows you to make tests use OAuth only, SAS only, etc.
requestedCredentialTypesSrc []common.CredentialType,
requestedCredentialTypesDst []common.CredentialType,
p params,
hs *hooks,
fs testFiles,
// TODO: do we need something here to explicitly say that we expect success or failure? For now, we are just inferring that from the elements of sourceFiles
destAccountType AccountType,
srcAccountType AccountType,
scenarioSuffix string) {
// enable this if we want parents in parallel: t.Parallel()
suiteName, testName := getTestName(t)
if suiteName == "" {
t.Errorf("To group our tests cleanly, our test names should be of the form: TestXxx_Yyy..., where Xxx matches one of the words in the (underscore-separated) name of the containing file. '%s' does not follow that rule",
t.Name())
}
// construct all the scenarios
scenarios := make([]scenario, 0)
for _, op := range operations.getValues() {
if op == eOperation.Resume() || op == eOperation.Cancel() {
continue
}
seenFromTos := make(map[common.FromTo]bool)
fromTos := testFromTo.getValues(op)
for _, fromTo := range fromTos {
// dedupe the scenarios
if _, ok := seenFromTos[fromTo]; ok {
continue
}
seenFromTos[fromTo] = true
credentialTypes := getValidCredCombinationsForFromTo(fromTo, requestedCredentialTypesSrc, requestedCredentialTypesDst, []AccountType{srcAccountType, destAccountType})
for _, credTypes := range credentialTypes {
// Create unique name for generating container names
compactScenarioName := fmt.Sprintf("%.4s-%s-%c-%c%c", suiteName, testName, op.String()[0], fromTo.From().String()[0], fromTo.To().String()[0])
fullScenarioName := fmt.Sprintf("%s.%s.%s-%s%s", suiteName, testName, op.String(), fromTo.From().String(), fromTo.To().String())
// Sub-test name is not globally unique (it doesn't need to be) but it is more human-readable
subtestName := fmt.Sprintf("%s-%s", op, fromTo)
hsToUse := hooks{}
if hs != nil {
hsToUse = *hs
}
if scenarioSuffix != "" {
subtestName += "-" + scenarioSuffix
}
usedSrc, usedDst := srcAccountType, destAccountType
if fromTo.From() == common.ELocation.BlobFS() {
// switch to an account made for dfs
usedSrc = EAccountType.HierarchicalNamespaceEnabled()
}
if fromTo.To() == common.ELocation.BlobFS() {
// switch to an account made for dfs
usedDst = EAccountType.HierarchicalNamespaceEnabled()
}
s := scenario{
srcAccountType: usedSrc,
destAccountType: usedDst,
subtestName: subtestName,
compactScenarioName: compactScenarioName,
fullScenarioName: fullScenarioName,
operation: op,
fromTo: fromTo,
credTypes: credTypes,
validate: validate,
p: p, // copies them, because they are a struct. This is what we need, since they may be morphed while running
hs: hsToUse,
fs: fs.DeepCopy(),
needResume: operations&eOperation.Resume() != 0,
needCancel: operations&eOperation.Cancel() != 0,
stripTopDir: p.stripTopDir,
}
scenarios = append(scenarios, s)
}
}
}
logErr := logTestSummary(suiteName, testName, operations.includes(eOperation.Copy()), operations.includes(eOperation.Sync()), testFromTo, len(scenarios))
if logErr != nil {
t.Errorf("Error logging to test summary file: %s", logErr)
}
// run them in parallel if not debugging, but sequentially (for easier debugging) if a debugger is attached
parallel := !isLaunchedByDebugger && !p.disableParallelTesting // this only works if gops.exe is on your path. See azcopyDebugHelper.go for instructions.
for _, s := range scenarios {
// use t.Run to get proper sub-test support
t.Run(s.subtestName, func(t *testing.T) {
sen := s // capture to separate var inside the loop, for the parallel case
credNames := fmt.Sprintf("%s-%s", s.credTypes[0].String(), s.credTypes[1].String())
t.Run(credNames, func(t *testing.T) {
if parallel {
t.Parallel() // tell testing that it can run stuff in parallel with us
}
// set asserter now (and only now), since before this point we don't have the right "t"
sen.a = &testingAsserter{
t: t,
fullScenarioName: sen.fullScenarioName,
compactScenarioName: sen.compactScenarioName,
}
if hs != nil {
sen.runHook(hs.beforeTestRun)
}
sen.Run()
})
})
}
}