func RunScenarios()

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()
			})
		})
	}
}