framework.go 4.3 KB

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