coordinator.go 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. package executor
  2. import (
  3. "errors"
  4. "fmt"
  5. "log"
  6. "strings"
  7. "sync"
  8. "github.com/smartystreets/goconvey/web/server/contract"
  9. )
  10. type concurrentCoordinator struct {
  11. batchSize int
  12. queue chan *contract.Package
  13. folders []*contract.Package
  14. shell contract.Shell
  15. waiter sync.WaitGroup
  16. }
  17. func (self *concurrentCoordinator) ExecuteConcurrently() {
  18. self.enlistWorkers()
  19. self.scheduleTasks()
  20. self.awaitCompletion()
  21. }
  22. func (self *concurrentCoordinator) enlistWorkers() {
  23. for i := 0; i < self.batchSize; i++ {
  24. self.waiter.Add(1)
  25. go self.worker(i)
  26. }
  27. }
  28. func (self *concurrentCoordinator) worker(id int) {
  29. for folder := range self.queue {
  30. packageName := strings.Replace(folder.Name, "\\", "/", -1)
  31. if !folder.Active() {
  32. log.Printf("Skipping concurrent execution: %s\n", packageName)
  33. continue
  34. }
  35. if folder.HasImportCycle {
  36. message := fmt.Sprintf("can't load package: import cycle not allowed\npackage %s\n\timports %s", packageName, packageName)
  37. log.Println(message)
  38. folder.Output, folder.Error = message, errors.New(message)
  39. } else {
  40. log.Printf("Executing concurrent tests: %s\n", packageName)
  41. folder.Output, folder.Error = self.shell.GoTest(folder.Path, packageName, folder.BuildTags, folder.TestArguments)
  42. }
  43. }
  44. self.waiter.Done()
  45. }
  46. func (self *concurrentCoordinator) scheduleTasks() {
  47. for _, folder := range self.folders {
  48. self.queue <- folder
  49. }
  50. }
  51. func (self *concurrentCoordinator) awaitCompletion() {
  52. close(self.queue)
  53. self.waiter.Wait()
  54. }
  55. func newConcurrentCoordinator(folders []*contract.Package, batchSize int, shell contract.Shell) *concurrentCoordinator {
  56. self := new(concurrentCoordinator)
  57. self.queue = make(chan *contract.Package)
  58. self.folders = folders
  59. self.batchSize = batchSize
  60. self.shell = shell
  61. return self
  62. }