github.com/swaros/contxt/module/taskrun@v0.0.0-20240305083542-3dbd4436ac40/cmdflow_test.go (about)

     1  package taskrun_test
     2  
     3  import (
     4  	"os"
     5  	"strings"
     6  	"testing"
     7  
     8  	"github.com/swaros/contxt/module/configure"
     9  	"github.com/swaros/contxt/module/dirhandle"
    10  	"github.com/swaros/contxt/module/taskrun"
    11  )
    12  
    13  type RuntimeGroupExpected struct {
    14  	Contains []string
    15  }
    16  
    17  type TestRuntimeGroup struct {
    18  	tests []RuntimeGroupExpected
    19  }
    20  
    21  func listHaveString(lookFor string, list []string) bool {
    22  	for _, s := range list {
    23  		if s == lookFor {
    24  			return true
    25  		}
    26  	}
    27  	return false
    28  }
    29  
    30  func listContainsEach(lista, listb []string) (string, bool) {
    31  	for _, chk := range lista {
    32  		if !listHaveString(chk, listb) {
    33  			return chk, false
    34  		}
    35  	}
    36  	return "", true
    37  }
    38  
    39  func sliceList(offset int, list []string) ([]string, []string) {
    40  	var newList []string
    41  	var restList []string
    42  	for i, cont := range list {
    43  		if i < offset {
    44  			newList = append(newList, cont)
    45  		} else {
    46  			restList = append(restList, cont)
    47  		}
    48  	}
    49  	return newList, restList
    50  }
    51  
    52  func assertRuntimeGroup(t *testing.T, path string, target string, testGroup TestRuntimeGroup) bool {
    53  	tresult := true
    54  	folderRunner(path, t, func(t *testing.T) {
    55  		taskrun.RunTargets(target, true)
    56  		result := taskrun.GetPH("teststr")
    57  		resultArr := strings.Split(result, ":")
    58  
    59  		//offset := 0
    60  		for tbIndex, runtimeCheck := range testGroup.tests {
    61  			var checkList []string
    62  			testLen := len(runtimeCheck.Contains) // how many entries we have to check
    63  			if testLen <= len(resultArr) {        // do we have enough entries in the result array?
    64  				checkList, resultArr = sliceList(len(runtimeCheck.Contains), resultArr)
    65  				if missingStr, ok := listContainsEach(checkList, runtimeCheck.Contains); ok == false {
    66  					t.Error("missing ", missingStr, " in test block ", tbIndex, " got ", checkList, " expected", runtimeCheck.Contains)
    67  					tresult = false
    68  				}
    69  			}
    70  		}
    71  
    72  	})
    73  
    74  	return tresult
    75  }
    76  
    77  func TestIssue58(t *testing.T) {
    78  	folderRunner("./../../docs/test/issue58", t, func(t *testing.T) {
    79  
    80  		taskrun.RunTargets("test1", true)
    81  		res := taskrun.GetPH("RUN.test1.LOG.LAST")
    82  		if res != "full check john miller" {
    83  			t.Error("unexpected result [", res, "]")
    84  		}
    85  
    86  		taskrun.RunTargets("start", true)
    87  		test1Result := taskrun.GetPH("RUN.start.LOG.LAST")
    88  		if test1Result != "hello world" {
    89  			t.Error("result 2 should be 'hello world'.[", test1Result, "]")
    90  		}
    91  
    92  		taskrun.RunTargets("replace", true)
    93  		rep := taskrun.GetPH("RUN.replace.LOG.LAST")
    94  		if rep != "[testcase /usr - mother]" {
    95  			t.Error("the replacing of inline variables in defined variables is not working")
    96  		}
    97  	})
    98  }
    99  
   100  func TestMultipleTargets(t *testing.T) {
   101  	folderRunner("./../../docs/test/01multi", t, func(t *testing.T) {
   102  		taskrun.RunTargets("task", true)
   103  		test1Result := taskrun.GetPH("RUN.task.LOG.LAST")
   104  		if test1Result != "hello 2" {
   105  			t.Error("result 2 should be 'hello 2'.", test1Result)
   106  		}
   107  	})
   108  }
   109  
   110  func TestMultipleTargetsOs(t *testing.T) {
   111  	folderRunner("./../../docs/test/02multi", t, func(t *testing.T) {
   112  		taskrun.RunTargets("task", true)
   113  		test1Result := taskrun.GetPH("RUN.task.LOG.LAST")
   114  		if configure.GetOs() == "linux" {
   115  			if test1Result != "hello linux" {
   116  				t.Error("result 2 should be 'hello 2'. got[", test1Result, "]")
   117  			}
   118  		}
   119  	})
   120  }
   121  
   122  func TestRunIfEquals(t *testing.T) {
   123  	folderRunner("./../../docs/test/ifequals", t, func(t *testing.T) {
   124  		taskrun.RunTargets("check-eq", true)
   125  		test1Result := taskrun.GetPH("RUN.check-eq.LOG.LAST")
   126  		if test1Result != "inline" {
   127  			t.Error("result 2 should be 'inline'.", test1Result)
   128  		}
   129  
   130  		taskrun.RunTargets("check-noeq", true)
   131  		test2Result := taskrun.GetPH("RUN.check-noeq.LOG.LAST")
   132  		if test2Result != "start2" {
   133  			t.Error("result 2 should be 'start2'.", test2Result)
   134  		}
   135  	})
   136  }
   137  
   138  func TestVariableReset(t *testing.T) {
   139  	folderRunner("./../../docs/test/valueRedefine", t, func(t *testing.T) {
   140  		taskrun.RunTargets("case1", true)
   141  		test1Result := taskrun.GetPH("RUN.case1.LOG.LAST")
   142  		if test1Result != "initial" {
   143  			t.Error("result 1 should be 'initial'.", test1Result)
   144  		}
   145  
   146  		taskrun.RunTargets("case2", true)
   147  		test2Result := taskrun.GetPH("RUN.case2.LOG.LAST")
   148  		if test2Result != "in-case-2" {
   149  			t.Error("result 2 should be 'in-case-2'.", test1Result)
   150  		}
   151  
   152  		taskrun.RunTargets("case1,case2", true)
   153  		test3Result := taskrun.GetPH("RUN.case2.LOG.LAST")
   154  		if test3Result != "in-case-2" {
   155  			t.Error("result 2 should be 'in-case-2'.", test1Result)
   156  		}
   157  
   158  		// testing main variables do not reset already changes variables
   159  		taskrun.RunTargets("case2,case1", true)
   160  		test4Result := taskrun.GetPH("RUN.case2.LOG.LAST")
   161  		if test4Result != "in-case-2" {
   162  			t.Error("result 2 should be 'in-case-2'.", test1Result)
   163  		}
   164  
   165  		test5Result := taskrun.GetPH("RUN.case1.LOG.LAST")
   166  		if test5Result != "in-case-2" {
   167  			t.Error("result 2 should be 'in-case-2'.", test1Result)
   168  		}
   169  	})
   170  }
   171  
   172  func TestCase0(t *testing.T) {
   173  	caseRunner("0", t, func(t *testing.T) {
   174  		taskrun.RunTargets("test1,test2", true)
   175  		test1Result := taskrun.GetPH("RUN.test1.LOG.LAST")
   176  		if test1Result == "" {
   177  			t.Error("result 1 should not be empty.", test1Result)
   178  		}
   179  
   180  		test2Result := taskrun.GetPH("RUN.test2.LOG.LAST")
   181  		if test2Result == "" {
   182  			t.Error("result 2 should not be empty.", test2Result)
   183  		}
   184  
   185  		if test2Result != "runs" {
   186  			t.Error("result 2 should be 'runs' instead we got.", "["+test2Result+"]")
   187  		}
   188  	})
   189  }
   190  
   191  func TestRunTargetCase1(t *testing.T) {
   192  
   193  	caseRunner("1", t, func(t *testing.T) {
   194  		taskrun.RunTargets("case1_1,case1_2", true)
   195  		test1Result := taskrun.GetPH("RUN.case1_1.LOG.LAST")
   196  		if test1Result == "" {
   197  			t.Error("result 1 should not be empty.", test1Result)
   198  		}
   199  
   200  		test2Result := taskrun.GetPH("RUN.case1_2.LOG.LAST")
   201  		if test2Result == "" {
   202  			t.Error("result 2 should not be empty.", test2Result)
   203  		}
   204  
   205  		if test2Result != "runs" {
   206  			t.Error("result 2 should be 'runs' instead we got.", test2Result)
   207  		}
   208  
   209  		scriptLast := taskrun.GetPH("RUN.SCRIPT_LINE")
   210  		if scriptLast != "echo runs" {
   211  			t.Error("unexpected result [", scriptLast, "]")
   212  		}
   213  	})
   214  
   215  }
   216  
   217  func TestRunTargetCase2(t *testing.T) {
   218  
   219  	caseRunner("2", t, func(t *testing.T) {
   220  		taskrun.RunTargets("base", true)
   221  		test1Result := taskrun.GetPH("RUN.base.LOG.HIT")
   222  		if test1Result != "start-task-2" {
   223  			t.Error("unexpected result ", test1Result)
   224  		}
   225  
   226  		test2Result := taskrun.GetPH("RUN.task-2.LOG.LAST")
   227  		if test2Result != "im-task-2" {
   228  			t.Error("unexpected result [", test2Result, "]")
   229  		}
   230  	})
   231  }
   232  
   233  // TBH: not sure if these is not too specific
   234  /*
   235  func TestRunTargetCase3(t *testing.T) {
   236  	// testing PID of my own and the parent process
   237  	if configure.GetOs() == "windows" {
   238  		return
   239  	}
   240  	caseRunner("3", t, func(t *testing.T) {
   241  		taskrun.RunTargets("base", true)
   242  		test1Result := taskrun.GetPH("RUN.base.LOG.HIT")
   243  		if test1Result != "launch" {
   244  			t.Error("unexpected result ", test1Result)
   245  		}
   246  		pid_1 := taskrun.GetPH("RUN.base.LOG.LAST")
   247  		pid_2 := taskrun.GetPH("RUN.task-2.LOG.LAST")
   248  		if pid_2 != pid_1 {
   249  			t.Error("PID should be the same [", pid_1, " != ", pid_2, "]")
   250  		}
   251  	})
   252  
   253  }*/
   254  
   255  func TestCase4(t *testing.T) {
   256  	caseRunner("4", t, func(t *testing.T) {
   257  		//stopped because log entrie to big
   258  		taskrun.RunTargets("base", true)
   259  		log := taskrun.GetPH("RUN.base.LOG.LAST")
   260  		if log != "sub 4-6" {
   261  			t.Error("last log entrie should not be:", log)
   262  		}
   263  
   264  		taskrun.RunTargets("contains", true)
   265  		log = taskrun.GetPH("RUN.contains.LOG.LAST")
   266  		if log != "come and die" {
   267  			t.Error("last log entrie should not be", log)
   268  		}
   269  	})
   270  }
   271  
   272  func TestCase5(t *testing.T) {
   273  	caseRunner("5", t, func(t *testing.T) {
   274  		//contains a mutliline shell script
   275  		taskrun.RunTargets("base", true)
   276  		log := taskrun.GetPH("RUN.base.LOG.LAST")
   277  		if log == "" {
   278  			t.Error("got empty result. that is not expected")
   279  		}
   280  		if log != "line4" {
   281  			t.Error("expected 'line4'...but got ", log)
   282  		}
   283  	})
   284  }
   285  
   286  // testing the thread run. do we wait for the subjobs also if they run longer then then main Task?
   287  func TestCase6(t *testing.T) {
   288  	caseRunner("6", t, func(t *testing.T) {
   289  		taskrun.RunTargets("base", true)
   290  		log := taskrun.GetPH("RUN.sub.LOG.LAST")
   291  		if log != "sub-end" {
   292  			t.Error("failed wait for ending subrun. last log entrie should be 'sub-end' got [", log, "] instead")
   293  		}
   294  
   295  	})
   296  }
   297  
   298  // testing error handling by script fails
   299  func TestCase7(t *testing.T) {
   300  	caseRunner("7", t, func(t *testing.T) {
   301  		taskrun.RunTargets("base", true)
   302  		logMain := taskrun.GetPH("RUN.base.LOG.LAST")
   303  		if logMain != "done-main" {
   304  			t.Error("last runstep should be excuted. but stopped on:", logMain)
   305  		}
   306  
   307  		log := taskrun.GetPH("RUN.sub.LOG.LAST")
   308  		if log == "sub-end" {
   309  			t.Error("the script runs without erros, but hey have an error. script have to stop. log=", log)
   310  		}
   311  
   312  	})
   313  }
   314  
   315  // testing on error behavior for the stop reasons
   316  func TestCase71(t *testing.T) {
   317  	assertCaseLogLastEquals(t, "7", "trigger", "two")                   // testing outpout match
   318  	assertCaseLogLastEquals(t, "7", "len", "123")                       // test onoutLess
   319  	assertCaseLogLastEquals(t, "7", "lenmore", "b123456abcdefghijklmn") // test onoutMore
   320  }
   321  
   322  // test variables. replace set at config variables to hallo-welt
   323  func TestCase8(t *testing.T) {
   324  	caseRunner("8", t, func(t *testing.T) {
   325  		taskrun.RunTargets("base", true)
   326  		logMain := taskrun.GetPH("RUN.base.LOG.LAST")
   327  		if logMain != "hallo-welt" {
   328  			t.Error("variable should be replaced. but got:", logMain)
   329  		}
   330  	})
   331  }
   332  
   333  // test variables. replace set at config variables to hallo-welt but then overwrittn in task to hello-world
   334  func TestCase9(t *testing.T) {
   335  	caseRunner("9", t, func(t *testing.T) {
   336  		taskrun.RunTargets("base,test2", true)
   337  		logMain := taskrun.GetPH("RUN.base.LOG.LAST")
   338  		if logMain != "hello-world" {
   339  			t.Error("variable should be replaced. but got:", logMain)
   340  		}
   341  		test2 := taskrun.GetPH("RUN.test2.LOG.LAST")
   342  		if test2 != "lets go" {
   343  			t.Error("placeholder was not used in task variables. got:[", test2, "]")
   344  		}
   345  	})
   346  }
   347  
   348  func TestCase12Requires(t *testing.T) {
   349  	caseRunner("12", t, func(t *testing.T) {
   350  		os.Setenv("TESTCASE_12_VAL", "HELLO")
   351  		taskrun.RunTargets("test1,test2,test3,test4,test5,test6", true)
   352  		logMain := taskrun.GetPH("RUN.test1.LOG.LAST")
   353  		if logMain != "run_a" {
   354  			t.Error("got unexpected result:", logMain)
   355  		}
   356  
   357  		test2 := taskrun.GetPH("RUN.test2.LOG.LAST")
   358  		if test2 != "" {
   359  			t.Error("got unexpected result for test2. got:", test2, "test should not run because of checking file")
   360  		}
   361  
   362  		test3 := taskrun.GetPH("RUN.test3.LOG.LAST")
   363  		if test3 != "" {
   364  			t.Error("got unexpected result for test3. got:", test3, "test should not run because env-var check")
   365  		}
   366  
   367  		test4 := taskrun.GetPH("RUN.test4.LOG.LAST")
   368  		if test4 != "run_d" {
   369  			t.Error("got unexpected result for test4. got:", test4, "test should run because env-var check")
   370  		}
   371  
   372  		test5 := taskrun.GetPH("RUN.test5.LOG.LAST")
   373  		if test5 != "" {
   374  			t.Error("got unexpected result for test5. got:", test5, "test should not run because variable check")
   375  		}
   376  
   377  		varValue := taskrun.GetPH("test_var")
   378  		if varValue == "HELLO_KLAUS" {
   379  			t.Error("Expected value 'HELLO_KLAUS' not in placeholder 'test_var'. got instead: ", varValue)
   380  		}
   381  		test6 := taskrun.GetPH("RUN.test6.LOG.LAST")
   382  		if test6 != "" {
   383  			t.Error("got unexpected result for test6. got:[", test6, "]test should run because variable check")
   384  		}
   385  	})
   386  }
   387  
   388  func TestCase13Next(t *testing.T) {
   389  	caseRunner("13", t, func(t *testing.T) {
   390  
   391  		taskrun.RunTargets("start", true)
   392  		logMain := taskrun.GetPH("RUN.start.LOG.LAST")
   393  		if logMain != "start" {
   394  			t.Error("got unexpected result:(", logMain, ")")
   395  		}
   396  
   397  		test2 := taskrun.GetPH("RUN.next_a.LOG.LAST")
   398  		if test2 != "run-a" {
   399  			t.Error("got unexpected result for test2. got:(", test2, ")")
   400  		}
   401  
   402  		test := taskrun.GetPH("RUN.next_b.LOG.LAST")
   403  		if test != "run-b" {
   404  			t.Error("got unexpected result for test3. got:(", test, ")")
   405  		}
   406  
   407  		test = taskrun.GetPH("RUN.next_c.LOG.LAST")
   408  		if test != "run-c" {
   409  			t.Error("got unexpected result for test4. got:(", test, ")")
   410  		}
   411  
   412  	})
   413  }
   414  
   415  func TestCase14Imports(t *testing.T) {
   416  	caseRunner("14", t, func(t *testing.T) {
   417  
   418  		taskrun.RunTargets("start,usertest", true)
   419  		check := taskrun.GetJSONPathValueString("import.yaml", "testdata.check")
   420  		if check != "hello" {
   421  			t.Error("expect hello but got", check)
   422  		}
   423  
   424  		outcome := taskrun.GetPH("RUN.start.LOG.LAST")
   425  		if outcome != "hello world" {
   426  			t.Error("import looks not working. got ", outcome)
   427  		}
   428  
   429  		usertest := taskrun.GetPH("RUN.usertest.LOG.LAST")
   430  		if usertest != "hello john miller" {
   431  			t.Error("user data import looks not working. got ", usertest)
   432  		}
   433  	})
   434  }
   435  
   436  func TestCase15Needs(t *testing.T) {
   437  	caseRunner("15", t, func(t *testing.T) {
   438  
   439  		taskrun.RunTargets("start", true)
   440  
   441  		usertest := taskrun.GetPH("RUN.start.LOG.LAST")
   442  		needOneRuns := taskrun.GetPH("RUN.need_one.LOG.LAST")
   443  		needTwoRuns := taskrun.GetPH("RUN.need_two.LOG.LAST")
   444  		if needOneRuns != "<<< 1 >>> done need_one" {
   445  			t.Error("NEEDS needOne should be executed [done need_one] we got : ", needOneRuns)
   446  		}
   447  		if needTwoRuns != "<<< 2 >>> done need_two" {
   448  			t.Error("NEEDS needTwo should be executed [done need_two] we got : ", needTwoRuns)
   449  		}
   450  
   451  		if usertest != "the-main-task" {
   452  			t.Error("did not get expected result instead [the-main-task] we got : ", usertest)
   453  		}
   454  	})
   455  }
   456  
   457  func TestCase16WorkingDir(t *testing.T) {
   458  	caseRunner("16", t, func(t *testing.T) {
   459  		old, derr := dirhandle.Current()
   460  		if derr != nil {
   461  			t.Error(derr)
   462  		}
   463  		taskrun.RunTargets("origin_dir", true)
   464  		origin_dir := clearStrings(taskrun.GetPH("RUN.origin_dir.LOG.LAST"))
   465  		oldChkStr := clearStrings(old)
   466  
   467  		// strToUpper required on windows because of differents in drive letter
   468  		if !strings.EqualFold(strings.ToUpper(origin_dir), strings.ToUpper(oldChkStr)) {
   469  			t.Error("do not get the expected folder ", oldChkStr, origin_dir)
   470  		}
   471  
   472  		taskrun.RunTargets("sub_a", true)
   473  		expected := "testcase_run_check_7725569sjghfghf"
   474  		current := taskrun.GetPH("RUN.sub_a.LOG.LAST")
   475  		if current != expected {
   476  			t.Error("we expected file content from test.txt in subfolder sub_a which is ", expected, " but got ", current)
   477  		}
   478  
   479  		newDir, nerr := dirhandle.Current()
   480  		if nerr != nil {
   481  			t.Error(derr)
   482  		}
   483  
   484  		if newDir != old {
   485  			t.Error("directory have to beeing set back to old dir after rinning task with a workingdir. but we are still at ", newDir)
   486  		}
   487  
   488  	})
   489  }
   490  
   491  func TestStringMatcher(t *testing.T) {
   492  	// positive expectations
   493  	if !taskrun.StringMatchTest("=test", "test") {
   494  		t.Error("expect TRUE, =test should match with test")
   495  	}
   496  
   497  	if !taskrun.StringMatchTest("test", "test") {
   498  		t.Error("expect TRUE, test should not match with test")
   499  	}
   500  
   501  	if !taskrun.StringMatchTest(">50", "51") {
   502  		t.Error("expect TRUE, 51 should accepted as greater then 50")
   503  	}
   504  
   505  	if !taskrun.StringMatchTest("<50", "49") {
   506  		t.Error("expect TRUE, 49 should accepted as lower then 50")
   507  	}
   508  	if !taskrun.StringMatchTest("?", "something") {
   509  		t.Error("expect TRUE, ? should match with anything")
   510  	}
   511  
   512  	// negative tests result expected
   513  	if taskrun.StringMatchTest("=test", "test2") {
   514  		t.Error("expect FALSE, =test should not match with test2")
   515  	}
   516  
   517  	if taskrun.StringMatchTest("!test", "test") {
   518  		t.Error("expect FALSE, !test should (not) match with test by condition")
   519  	}
   520  
   521  	if taskrun.StringMatchTest(">test20", "test15") {
   522  		t.Error("expect FALSE, test20 is greater then test15")
   523  	}
   524  
   525  	if taskrun.StringMatchTest("<test20", "test35") {
   526  		t.Error("expect FALSE, test20 is lower then test35")
   527  	}
   528  
   529  	if taskrun.StringMatchTest("", "something") {
   530  		t.Error("expect FALSE, empty should not match")
   531  	}
   532  
   533  	if !taskrun.StringMatchTest("", "") {
   534  		t.Error("expect TRUE, empty should match to empty")
   535  	}
   536  
   537  	if taskrun.StringMatchTest("*", "") {
   538  		t.Error("expect FALSE, not-empty (*) placeholder should not match with empty")
   539  	}
   540  
   541  	if !taskrun.StringMatchTest("*", "something") {
   542  		t.Error("expect TRUE, not-empty placeholder should match with something")
   543  	}
   544  }
   545  
   546  func TestNeedWithArgs(t *testing.T) {
   547  	folderRunner("./../../docs/test/needWArgs", t, func(t *testing.T) {
   548  		taskrun.RunTargets("test-need", false)
   549  
   550  	})
   551  }
   552  
   553  func TestJsonExec(t *testing.T) {
   554  	folderRunner("./../../docs/test/execjson", t, func(t *testing.T) {
   555  		taskrun.RunTargets("test-load", false)
   556  		found, json := taskrun.GetData("JSON")
   557  		if !found {
   558  			t.Error("expected to find JSON data")
   559  		} else {
   560  			if _, ok := json["0"]; !ok {
   561  				t.Error("expected to find key 0 in JSON data")
   562  			}
   563  		}
   564  
   565  		lastLogLine := taskrun.GetPH("RUN.test-load.LOG.LAST")
   566  		if lastLogLine != "buildkit.dockerfile.v0" {
   567  			t.Error("expected to find buildkit.dockerfile.v0 in log")
   568  		}
   569  	})
   570  }
   571  
   572  func TestConcurrent(t *testing.T) {
   573  	expected := ""
   574  	folderRunner("./../../docs/test/01concurrent", t, func(t *testing.T) {
   575  		taskrun.RunTargets("main_a", false)
   576  		main_a := taskrun.GetPH("teststr")
   577  		expected = "BASE:MA:"
   578  		if main_a != expected {
   579  			t.Error("expected:", expected, " instead:", main_a)
   580  		}
   581  	})
   582  }
   583  
   584  func TestConcurrentMainB(t *testing.T) {
   585  	var test TestRuntimeGroup = TestRuntimeGroup{
   586  		[]RuntimeGroupExpected{
   587  			{
   588  				Contains: []string{"BASE"},
   589  			},
   590  			{
   591  				Contains: []string{"NB", "NA", "NC"},
   592  			},
   593  			{
   594  				Contains: []string{"MB"},
   595  			},
   596  		},
   597  	}
   598  	assertRuntimeGroup(t, "./../../docs/test/01concurrent", "main_b", test)
   599  }
   600  
   601  func TestConcurrentMainC(t *testing.T) {
   602  	var test TestRuntimeGroup = TestRuntimeGroup{
   603  		[]RuntimeGroupExpected{
   604  			{
   605  				Contains: []string{"BASE"}, // base fiirst at all
   606  			},
   607  			{
   608  				Contains: []string{"NB", "NA", "NC"}, // needs as second
   609  			},
   610  			{
   611  				Contains: []string{"MC", "TC", "TA", "TB"}, //anything else at the end unordered MC:TC:TA:TB:
   612  			},
   613  		},
   614  	}
   615  	assertRuntimeGroup(t, "./../../docs/test/01concurrent", "main_c", test)
   616  }
   617  
   618  func TestConcurrentMainD(t *testing.T) {
   619  	// BASE:NB:MC:TC:NA:TA:TB:NC:MD:
   620  	/*
   621  	 - id: main_d
   622  	    needs:
   623  	      - need_a
   624  	      - main_c
   625  	      - need_c
   626  	    script:
   627  	      - "#@add teststr MD:"
   628  	      - echo ${teststr}
   629  	*/
   630  	var test TestRuntimeGroup = TestRuntimeGroup{
   631  		[]RuntimeGroupExpected{
   632  			{
   633  				Contains: []string{"BASE"}, // base first at all
   634  			},
   635  			{
   636  				Contains: []string{"NB"}, // need b first as it is a need of main_c
   637  			},
   638  			{
   639  				Contains: []string{"MC", "NC", "NA", "TC", "TA", "TB"}, //anything else at the end unordered
   640  			},
   641  			{
   642  				Contains: []string{"MD"}, // the last is main_d
   643  			},
   644  		},
   645  	}
   646  
   647  	// have to investigate why, but on windows
   648  	// the order of execution seems different.
   649  	// but the imortant order seems beeing intact
   650  	if configure.GetOs() == "windows" {
   651  		test = TestRuntimeGroup{
   652  			[]RuntimeGroupExpected{
   653  				{
   654  					Contains: []string{"BASE"}, // base first at all
   655  				},
   656  				{
   657  					Contains: []string{"NB", "MC", "NC", "NA", "TC", "TA", "TB"}, //anything else at the end unordered
   658  				},
   659  				{
   660  					Contains: []string{"MD"}, // the last is main_d
   661  				},
   662  			},
   663  		}
   664  	}
   665  
   666  	assertRuntimeGroup(t, "./../../docs/test/01concurrent", "main_d", test)
   667  }