github.com/onsi/ginkgo@v1.16.6-0.20211118180735-4e1925ba4c95/internal/internal_integration/parallel_test.go (about)

     1  package internal_integration_test
     2  
     3  import (
     4  	"time"
     5  
     6  	. "github.com/onsi/ginkgo"
     7  	"github.com/onsi/ginkgo/internal"
     8  	. "github.com/onsi/ginkgo/internal/test_helpers"
     9  	"github.com/onsi/ginkgo/types"
    10  	. "github.com/onsi/gomega"
    11  )
    12  
    13  var _ = Describe("Running tests in parallel", func() {
    14  	var conf2 types.SuiteConfig
    15  	var reporter2 *FakeReporter
    16  	var rt2 *RunTracker
    17  	var serialValidator chan interface{}
    18  
    19  	var fixture = func(rt *RunTracker, proc int) {
    20  		SynchronizedBeforeSuite(func() []byte {
    21  			rt.Run("before-suite-1")
    22  			return []byte("floop")
    23  		}, func(proc1Data []byte) {
    24  			rt.Run("before-suite-2 " + string(proc1Data))
    25  		})
    26  
    27  		It("A", rt.T("A", func() {
    28  			time.Sleep(10 * time.Millisecond)
    29  		}))
    30  		It("B", rt.T("B", func() {
    31  			time.Sleep(10 * time.Millisecond)
    32  		}))
    33  		It("C", rt.T("C", func() {
    34  			time.Sleep(10 * time.Millisecond)
    35  		}))
    36  		It("D", rt.T("D", func() {
    37  			time.Sleep(10 * time.Millisecond)
    38  		}))
    39  		It("E", rt.T("E", func() {
    40  			time.Sleep(10 * time.Millisecond)
    41  		}))
    42  		It("F", rt.T("F", func() {
    43  			time.Sleep(10 * time.Millisecond)
    44  		}))
    45  		Context("Ordered", Ordered, func() {
    46  			It("OA", rt.T("OA", func() {
    47  				time.Sleep(10 * time.Millisecond)
    48  			}))
    49  			It("OB", rt.T("OB", func() {
    50  				time.Sleep(10 * time.Millisecond)
    51  			}))
    52  			It("OC", rt.T("OC", func() {
    53  				time.Sleep(10 * time.Millisecond)
    54  			}))
    55  		})
    56  		It("G", Serial, rt.T("G", func() {
    57  			Ω(serialValidator).Should(BeClosed())
    58  			time.Sleep(10 * time.Millisecond)
    59  		}))
    60  		It("H", Serial, rt.T("H", func() {
    61  			Ω(serialValidator).Should(BeClosed())
    62  			time.Sleep(10 * time.Millisecond)
    63  		}))
    64  		It("I", Serial, rt.T("I", func() {
    65  			Ω(serialValidator).Should(BeClosed())
    66  			time.Sleep(10 * time.Millisecond)
    67  		}))
    68  		Context("Ordered and Serial", Ordered, Serial, func() {
    69  			It("OSA", rt.T("OSA", func() {
    70  				Ω(serialValidator).Should(BeClosed())
    71  				time.Sleep(10 * time.Millisecond)
    72  			}))
    73  			It("OSB", rt.T("OSB", func() {
    74  				Ω(serialValidator).Should(BeClosed())
    75  				time.Sleep(10 * time.Millisecond)
    76  			}))
    77  		})
    78  
    79  		SynchronizedAfterSuite(rt.T("after-suite-1", func() {
    80  			if proc == 2 {
    81  				close(serialValidator)
    82  			}
    83  		}), rt.T("after-suite-2"))
    84  	}
    85  
    86  	BeforeEach(func() {
    87  		serialValidator = make(chan interface{})
    88  		//set up configuration for proc 1 and proc 2
    89  
    90  		//SetUpForParallel starts up a server, sets up a client, and sets up the exitChannels map - they're all cleaned up automatically after the test
    91  		SetUpForParallel(2)
    92  
    93  		conf.ParallelProcess = 1
    94  		conf.RandomizeAllSpecs = true
    95  		conf.RandomSeed = 17
    96  
    97  		conf2 = conf //makes a copy
    98  		conf2.ParallelProcess = 2
    99  
   100  		// construct suite 1...
   101  		suite1 := internal.NewSuite()
   102  		WithSuite(suite1, func() {
   103  			fixture(rt, 1)
   104  			Ω(suite1.BuildTree()).Should(Succeed())
   105  		})
   106  
   107  		//now construct suite 2...
   108  		suite2 := internal.NewSuite()
   109  		rt2 = NewRunTracker()
   110  		WithSuite(suite2, func() {
   111  			fixture(rt2, 2)
   112  			Ω(suite2.BuildTree()).Should(Succeed())
   113  		})
   114  
   115  		finished := make(chan bool)
   116  		exit1 := exitChannels[1] //avoid a race around exitChannels access in a separate goroutine
   117  		//now launch suite 1...
   118  		go func() {
   119  			success, _ := suite1.Run("proc 1", Label("TopLevelLabel"), "/path/to/suite", failer, reporter, writer, outputInterceptor, interruptHandler, client, conf)
   120  			finished <- success
   121  			close(exit1)
   122  		}()
   123  
   124  		//and launch suite 2...
   125  		reporter2 = &FakeReporter{}
   126  		exit2 := exitChannels[2] //avoid a race around exitChannels access in a separate goroutine
   127  		go func() {
   128  			success, _ := suite2.Run("proc 2", Label("TopLevelLabel"), "/path/to/suite", internal.NewFailer(), reporter2, writer, outputInterceptor, interruptHandler, client, conf2)
   129  			finished <- success
   130  			close(exit2)
   131  		}()
   132  
   133  		// eventually both suites should finish (and succeed)...
   134  		Eventually(finished).Should(Receive(Equal(true)))
   135  		Eventually(finished).Should(Receive(Equal(true)))
   136  		// and now we're ready to make asserts on the various run trackers and reporters
   137  	})
   138  
   139  	It("distributes tests across the parallel procs and runs them", func() {
   140  		Ω(rt).Should(HaveRun("before-suite-1"))
   141  		Ω(rt).Should(HaveRun("before-suite-2 floop"))
   142  		Ω(rt).Should(HaveRun("after-suite-1"))
   143  		Ω(rt).Should(HaveRun("after-suite-2"))
   144  
   145  		Ω(rt2).ShouldNot(HaveRun("before-suite-1"))
   146  		Ω(rt2).Should(HaveRun("before-suite-2 floop"))
   147  		Ω(rt2).Should(HaveRun("after-suite-1"))
   148  		Ω(rt2).ShouldNot(HaveRun("after-suite-2"))
   149  
   150  		allRuns := append(rt.TrackedRuns(), rt2.TrackedRuns()...)
   151  		Ω(allRuns).Should(ConsistOf(
   152  			"before-suite-1", "before-suite-2 floop", "after-suite-1", "after-suite-2", "before-suite-2 floop", "after-suite-1",
   153  			"A", "B", "C", "D", "E", "F", "G", "H", "I", "OA", "OB", "OC", "OSA", "OSB", //all ran
   154  		))
   155  
   156  		Ω(reporter.Did.Names()).ShouldNot(BeEmpty())
   157  		Ω(reporter2.Did.Names()).ShouldNot(BeEmpty())
   158  		names := append(reporter.Did.Names(), reporter2.Did.Names()...)
   159  		Ω(names).Should(ConsistOf("A", "B", "C", "D", "E", "F", "G", "H", "I", "OA", "OB", "OC", "OSA", "OSB"))
   160  	})
   161  
   162  	It("only runs serial tests on proc 1, after the other proc has finished", func() {
   163  		names := reporter.Did.Names()
   164  		Ω(names).Should(ContainElements("G", "H", "I", "OSA", "OSB"))
   165  		for idx, name := range names {
   166  			if name == "OSA" {
   167  				Ω(names[idx+1]).Should(Equal("OSB"))
   168  				break
   169  			}
   170  		}
   171  		Ω(reporter2.Did.Names()).ShouldNot(ContainElements("G", "H", "I", "OSA", "OSB"))
   172  	})
   173  
   174  	It("it ensures specs in an ordered container run on the same process and are ordered", func() {
   175  		names1 := reporter.Did.Names()
   176  		names2 := reporter2.Did.Names()
   177  		in1, _ := ContainElement("OA").Match(names1)
   178  		winner := names1
   179  		if !in1 {
   180  			winner = names2
   181  		}
   182  		found := false
   183  		for idx, name := range winner {
   184  			if name == "OA" {
   185  				found = true
   186  				Ω(winner[idx+1]).Should(Equal("OB"))
   187  				Ω(winner[idx+2]).Should(Equal("OC"))
   188  				break
   189  			}
   190  		}
   191  		Ω(found).Should(BeTrue())
   192  	})
   193  
   194  	It("reports the correct statistics", func() {
   195  		Ω(reporter.End.PreRunStats.TotalSpecs).Should(Equal(14))
   196  		Ω(reporter2.End.PreRunStats.TotalSpecs).Should(Equal(14))
   197  		Ω(reporter.End.PreRunStats.SpecsThatWillRun).Should(Equal(14))
   198  		Ω(reporter2.End.PreRunStats.SpecsThatWillRun).Should(Equal(14))
   199  
   200  		Ω(reporter.End.SpecReports.WithLeafNodeType(types.NodeTypeIt).CountWithState(types.SpecStatePassed) +
   201  			reporter2.End.SpecReports.WithLeafNodeType(types.NodeTypeIt).CountWithState(types.SpecStatePassed)).Should(Equal(14))
   202  	})
   203  })