framework.go 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. package framework
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io/ioutil"
  6. "os"
  7. "path/filepath"
  8. "regexp"
  9. "strings"
  10. "text/template"
  11. "github.com/fatedier/frp/test/e2e/mock/server"
  12. "github.com/fatedier/frp/test/e2e/pkg/port"
  13. "github.com/fatedier/frp/test/e2e/pkg/process"
  14. "github.com/onsi/ginkgo"
  15. "github.com/onsi/ginkgo/config"
  16. )
  17. type Options struct {
  18. TotalParallelNode int
  19. CurrentNodeIndex int
  20. FromPortIndex int
  21. ToPortIndex int
  22. }
  23. type Framework struct {
  24. TempDirectory string
  25. // ports used in this framework indexed by port name.
  26. usedPorts map[string]int
  27. // record ports alloced by this framework and release them after each test
  28. allocedPorts []int
  29. // portAllocator to alloc port for this test case.
  30. portAllocator *port.Allocator
  31. // Multiple default mock servers used for e2e testing.
  32. mockServers *MockServers
  33. // To make sure that this framework cleans up after itself, no matter what,
  34. // we install a Cleanup action before each test and clear it after. If we
  35. // should abort, the AfterSuite hook should run all Cleanup actions.
  36. cleanupHandle CleanupActionHandle
  37. // beforeEachStarted indicates that BeforeEach has started
  38. beforeEachStarted bool
  39. serverConfPaths []string
  40. serverProcesses []*process.Process
  41. clientConfPaths []string
  42. clientProcesses []*process.Process
  43. // Manual registered mock servers.
  44. servers []server.Server
  45. // used to generate unique config file name.
  46. configFileIndex int64
  47. // envs used to start processes, the form is `key=value`.
  48. osEnvs []string
  49. }
  50. func NewDefaultFramework() *Framework {
  51. options := Options{
  52. TotalParallelNode: config.GinkgoConfig.ParallelTotal,
  53. CurrentNodeIndex: config.GinkgoConfig.ParallelNode,
  54. FromPortIndex: 20000,
  55. ToPortIndex: 50000,
  56. }
  57. return NewFramework(options)
  58. }
  59. func NewFramework(opt Options) *Framework {
  60. f := &Framework{
  61. portAllocator: port.NewAllocator(opt.FromPortIndex, opt.ToPortIndex, opt.TotalParallelNode, opt.CurrentNodeIndex-1),
  62. usedPorts: make(map[string]int),
  63. }
  64. ginkgo.BeforeEach(f.BeforeEach)
  65. ginkgo.AfterEach(f.AfterEach)
  66. return f
  67. }
  68. // BeforeEach create a temp directory.
  69. func (f *Framework) BeforeEach() {
  70. f.beforeEachStarted = true
  71. f.cleanupHandle = AddCleanupAction(f.AfterEach)
  72. dir, err := ioutil.TempDir(os.TempDir(), "frp-e2e-test-*")
  73. ExpectNoError(err)
  74. f.TempDirectory = dir
  75. f.mockServers = NewMockServers(f.portAllocator)
  76. if err := f.mockServers.Run(); err != nil {
  77. Failf("%v", err)
  78. }
  79. params := f.mockServers.GetTemplateParams()
  80. for k, v := range params {
  81. switch t := v.(type) {
  82. case int:
  83. f.usedPorts[k] = int(t)
  84. }
  85. }
  86. }
  87. func (f *Framework) AfterEach() {
  88. if !f.beforeEachStarted {
  89. return
  90. }
  91. RemoveCleanupAction(f.cleanupHandle)
  92. // stop processor
  93. for _, p := range f.serverProcesses {
  94. p.Stop()
  95. if TestContext.Debug {
  96. fmt.Println(p.ErrorOutput())
  97. fmt.Println(p.StdOutput())
  98. }
  99. }
  100. for _, p := range f.clientProcesses {
  101. p.Stop()
  102. if TestContext.Debug {
  103. fmt.Println(p.ErrorOutput())
  104. fmt.Println(p.StdOutput())
  105. }
  106. }
  107. f.serverProcesses = nil
  108. f.clientProcesses = nil
  109. // close default mock servers
  110. f.mockServers.Close()
  111. // close manual registered mock servers
  112. for _, s := range f.servers {
  113. s.Close()
  114. }
  115. // clean directory
  116. os.RemoveAll(f.TempDirectory)
  117. f.TempDirectory = ""
  118. f.serverConfPaths = []string{}
  119. f.clientConfPaths = []string{}
  120. // release used ports
  121. for _, port := range f.usedPorts {
  122. f.portAllocator.Release(port)
  123. }
  124. f.usedPorts = make(map[string]int)
  125. // release alloced ports
  126. for _, port := range f.allocedPorts {
  127. f.portAllocator.Release(port)
  128. }
  129. f.allocedPorts = make([]int, 0)
  130. // clear os envs
  131. f.osEnvs = make([]string, 0)
  132. }
  133. var portRegex = regexp.MustCompile(`{{ \.Port.*? }}`)
  134. // RenderPortsTemplate render templates with ports.
  135. //
  136. // Local: {{ .Port1 }}
  137. // Target: {{ .Port2 }}
  138. //
  139. // return rendered content and all allocated ports.
  140. func (f *Framework) genPortsFromTemplates(templates []string) (ports map[string]int, err error) {
  141. ports = make(map[string]int)
  142. for _, t := range templates {
  143. arrs := portRegex.FindAllString(t, -1)
  144. for _, str := range arrs {
  145. str = strings.TrimPrefix(str, "{{ .")
  146. str = strings.TrimSuffix(str, " }}")
  147. str = strings.TrimSpace(str)
  148. ports[str] = 0
  149. }
  150. }
  151. defer func() {
  152. if err != nil {
  153. for _, port := range ports {
  154. f.portAllocator.Release(port)
  155. }
  156. }
  157. }()
  158. for name := range ports {
  159. port := f.portAllocator.GetByName(name)
  160. if port <= 0 {
  161. return nil, fmt.Errorf("can't allocate port")
  162. }
  163. ports[name] = port
  164. }
  165. return
  166. }
  167. // RenderTemplates alloc all ports for port names placeholder.
  168. func (f *Framework) RenderTemplates(templates []string) (outs []string, ports map[string]int, err error) {
  169. ports, err = f.genPortsFromTemplates(templates)
  170. if err != nil {
  171. return
  172. }
  173. params := f.mockServers.GetTemplateParams()
  174. for name, port := range ports {
  175. params[name] = port
  176. }
  177. for name, port := range f.usedPorts {
  178. params[name] = port
  179. }
  180. for _, t := range templates {
  181. tmpl, err := template.New("").Parse(t)
  182. if err != nil {
  183. return nil, nil, err
  184. }
  185. buffer := bytes.NewBuffer(nil)
  186. if err = tmpl.Execute(buffer, params); err != nil {
  187. return nil, nil, err
  188. }
  189. outs = append(outs, buffer.String())
  190. }
  191. return
  192. }
  193. func (f *Framework) PortByName(name string) int {
  194. return f.usedPorts[name]
  195. }
  196. func (f *Framework) AllocPort() int {
  197. port := f.portAllocator.Get()
  198. ExpectTrue(port > 0, "alloc port failed")
  199. f.allocedPorts = append(f.allocedPorts, port)
  200. return port
  201. }
  202. func (f *Framework) ReleasePort(port int) {
  203. f.portAllocator.Release(port)
  204. }
  205. func (f *Framework) RunServer(portName string, s server.Server) {
  206. f.servers = append(f.servers, s)
  207. if s.BindPort() > 0 && portName != "" {
  208. f.usedPorts[portName] = s.BindPort()
  209. }
  210. err := s.Run()
  211. ExpectNoError(err, "RunServer: with PortName %s", portName)
  212. }
  213. func (f *Framework) SetEnvs(envs []string) {
  214. f.osEnvs = envs
  215. }
  216. func (f *Framework) WriteTempFile(name string, content string) string {
  217. filePath := filepath.Join(f.TempDirectory, name)
  218. err := ioutil.WriteFile(filePath, []byte(content), 0766)
  219. ExpectNoError(err)
  220. return filePath
  221. }