framework.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. package framework
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io/ioutil"
  6. "os"
  7. "regexp"
  8. "strings"
  9. "text/template"
  10. "github.com/fatedier/frp/test/e2e/pkg/port"
  11. "github.com/fatedier/frp/test/e2e/pkg/process"
  12. "github.com/onsi/ginkgo"
  13. "github.com/onsi/ginkgo/config"
  14. )
  15. type Options struct {
  16. TotalParallelNode int
  17. CurrentNodeIndex int
  18. FromPortIndex int
  19. ToPortIndex int
  20. }
  21. type Framework struct {
  22. TempDirectory string
  23. UsedPorts map[string]int
  24. portAllocator *port.Allocator
  25. // Multiple mock servers used for e2e testing.
  26. mockServers *MockServers
  27. // To make sure that this framework cleans up after itself, no matter what,
  28. // we install a Cleanup action before each test and clear it after. If we
  29. // should abort, the AfterSuite hook should run all Cleanup actions.
  30. cleanupHandle CleanupActionHandle
  31. // beforeEachStarted indicates that BeforeEach has started
  32. beforeEachStarted bool
  33. serverConfPaths []string
  34. serverProcesses []*process.Process
  35. clientConfPaths []string
  36. clientProcesses []*process.Process
  37. }
  38. func NewDefaultFramework() *Framework {
  39. options := Options{
  40. TotalParallelNode: config.GinkgoConfig.ParallelTotal,
  41. CurrentNodeIndex: config.GinkgoConfig.ParallelNode,
  42. FromPortIndex: 20000,
  43. ToPortIndex: 50000,
  44. }
  45. return NewFramework(options)
  46. }
  47. func NewFramework(opt Options) *Framework {
  48. f := &Framework{
  49. portAllocator: port.NewAllocator(opt.FromPortIndex, opt.ToPortIndex, opt.TotalParallelNode, opt.CurrentNodeIndex-1),
  50. }
  51. ginkgo.BeforeEach(f.BeforeEach)
  52. ginkgo.AfterEach(f.AfterEach)
  53. return f
  54. }
  55. // BeforeEach create a temp directory.
  56. func (f *Framework) BeforeEach() {
  57. f.beforeEachStarted = true
  58. f.cleanupHandle = AddCleanupAction(f.AfterEach)
  59. dir, err := ioutil.TempDir(os.TempDir(), "frpe2e-test-*")
  60. ExpectNoError(err)
  61. f.TempDirectory = dir
  62. f.mockServers = NewMockServers(f.portAllocator)
  63. if err := f.mockServers.Run(); err != nil {
  64. Failf("%v", err)
  65. }
  66. }
  67. func (f *Framework) AfterEach() {
  68. if !f.beforeEachStarted {
  69. return
  70. }
  71. RemoveCleanupAction(f.cleanupHandle)
  72. // stop processor
  73. for _, p := range f.serverProcesses {
  74. p.Stop()
  75. if TestContext.Debug {
  76. fmt.Println(p.ErrorOutput())
  77. fmt.Println(p.StdOutput())
  78. }
  79. }
  80. for _, p := range f.clientProcesses {
  81. p.Stop()
  82. if TestContext.Debug {
  83. fmt.Println(p.ErrorOutput())
  84. fmt.Println(p.StdOutput())
  85. }
  86. }
  87. f.serverProcesses = nil
  88. f.clientProcesses = nil
  89. // close mock servers
  90. f.mockServers.Close()
  91. // clean directory
  92. os.RemoveAll(f.TempDirectory)
  93. f.TempDirectory = ""
  94. f.serverConfPaths = nil
  95. f.clientConfPaths = nil
  96. // release used ports
  97. for _, port := range f.UsedPorts {
  98. f.portAllocator.Release(port)
  99. }
  100. f.UsedPorts = nil
  101. }
  102. var portRegex = regexp.MustCompile(`{{ \.Port.*? }}`)
  103. // RenderPortsTemplate render templates with ports.
  104. //
  105. // Local: {{ .Port1 }}
  106. // Target: {{ .Port2 }}
  107. //
  108. // return rendered content and all allocated ports.
  109. func (f *Framework) genPortsFromTemplates(templates []string) (ports map[string]int, err error) {
  110. ports = make(map[string]int)
  111. for _, t := range templates {
  112. arrs := portRegex.FindAllString(t, -1)
  113. for _, str := range arrs {
  114. str = strings.TrimPrefix(str, "{{ .")
  115. str = strings.TrimSuffix(str, " }}")
  116. str = strings.TrimSpace(str)
  117. ports[str] = 0
  118. }
  119. }
  120. defer func() {
  121. if err != nil {
  122. for _, port := range ports {
  123. f.portAllocator.Release(port)
  124. }
  125. }
  126. }()
  127. for name := range ports {
  128. port := f.portAllocator.Get()
  129. if port <= 0 {
  130. return nil, fmt.Errorf("can't allocate port")
  131. }
  132. ports[name] = port
  133. }
  134. return
  135. }
  136. func (f *Framework) RenderTemplates(templates []string) (outs []string, ports map[string]int, err error) {
  137. ports, err = f.genPortsFromTemplates(templates)
  138. if err != nil {
  139. return
  140. }
  141. params := f.mockServers.GetTemplateParams()
  142. for name, port := range ports {
  143. params[name] = port
  144. }
  145. for _, t := range templates {
  146. tmpl, err := template.New("").Parse(t)
  147. if err != nil {
  148. return nil, nil, err
  149. }
  150. buffer := bytes.NewBuffer(nil)
  151. if err = tmpl.Execute(buffer, params); err != nil {
  152. return nil, nil, err
  153. }
  154. outs = append(outs, buffer.String())
  155. }
  156. return
  157. }