flamingo.me/flamingo-commerce/v3@v3.11.0/test/integrationtest/helper.go (about)

     1  package integrationtest
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"log"
     7  	"net"
     8  	"net/http"
     9  	"net/url"
    10  	"os"
    11  	"strconv"
    12  	"sync"
    13  	"time"
    14  
    15  	"flamingo.me/dingo"
    16  	"github.com/gavv/httpexpect/v2"
    17  
    18  	"flamingo.me/flamingo/v3"
    19  	"flamingo.me/flamingo/v3/framework/config"
    20  	flamingoFramework "flamingo.me/flamingo/v3/framework/flamingo"
    21  	"flamingo.me/flamingo/v3/framework/web"
    22  )
    23  
    24  type (
    25  	testModule struct {
    26  		eventRouter flamingoFramework.EventRouter
    27  		router      *web.Router
    28  		server      *http.Server
    29  	}
    30  
    31  	//BootupInfo about the booted app
    32  	BootupInfo struct {
    33  		ShutdownFunc func()
    34  		Application  *flamingo.Application
    35  		BaseURL      string
    36  		Running      chan struct{}
    37  	}
    38  )
    39  
    40  // Side effect vars to get status and exchange stuff with the testModule
    41  var rw sync.Mutex
    42  
    43  var additionalConfig config.Map
    44  
    45  // Configure for your testModule in the app
    46  func (t *testModule) Inject(eventRouter flamingoFramework.EventRouter, router *web.Router) {
    47  	t.eventRouter = eventRouter
    48  	t.router = router
    49  }
    50  
    51  // Configure for your testModule in the app
    52  func (t *testModule) Configure(i *dingo.Injector) {
    53  	flamingoFramework.BindEventSubscriber(i).To(t)
    54  }
    55  
    56  // Notify gets notified by event router
    57  func (t *testModule) Notify(_ context.Context, event flamingoFramework.Event) {
    58  	switch event.(type) {
    59  	case *flamingoFramework.ShutdownEvent:
    60  		log.Printf("ShutdownEvent event received...")
    61  	}
    62  }
    63  
    64  // DefaultConfig of test module
    65  func (t *testModule) DefaultConfig() config.Map {
    66  	return additionalConfig
    67  }
    68  
    69  // shutdown until
    70  func (t *testModule) shutdownServer() {
    71  	log.Printf("Trigger ServerShutdownEvent...")
    72  	t.eventRouter.Dispatch(context.Background(), &flamingoFramework.ServerShutdownEvent{})
    73  	_ = t.server.Shutdown(context.Background())
    74  }
    75  
    76  // returns the port or error
    77  func (t *testModule) startServer(listenAndServeQuited chan struct{}) (string, error) {
    78  	port := os.Getenv("INTEGRATION_TEST_PORT")
    79  	if port == "" {
    80  		port = "0"
    81  	}
    82  
    83  	t.eventRouter.Dispatch(context.Background(), &flamingoFramework.ServerStartEvent{})
    84  	t.server = &http.Server{
    85  		Addr: ":" + port,
    86  	}
    87  
    88  	t.server.Handler = t.router.Handler()
    89  	listener, err := net.Listen("tcp", t.server.Addr)
    90  	if err != nil {
    91  		return "", err
    92  	}
    93  
    94  	listenerPort := listener.Addr().(*net.TCPAddr).Port
    95  
    96  	log.Printf("startServer on port %v", listenerPort)
    97  	go func() {
    98  		_ = t.server.Serve(listener)
    99  		listenAndServeQuited <- struct{}{}
   100  	}()
   101  	return strconv.Itoa(listenerPort), nil
   102  }
   103  
   104  // Bootup flamingo app with the given modules (and the config in folder given )
   105  func Bootup(modules []dingo.Module, configDir string, config config.Map) BootupInfo {
   106  	if configDir != "" {
   107  		if _, err := os.Stat(configDir); os.IsNotExist(err) {
   108  			panic("configdir: " + configDir + " does not exist")
   109  		}
   110  	}
   111  	rw.Lock()
   112  	defer rw.Unlock()
   113  	//add testModule that listens
   114  	modules = append(modules, new(testModule))
   115  	//rootArea := rootArea("config")
   116  	if len(os.Args) > 1 {
   117  		os.Args[1] = "serve"
   118  	}
   119  	additionalConfig = config
   120  
   121  	application, err := flamingo.NewApplication(modules, flamingo.ConfigDir(configDir))
   122  	if err != nil {
   123  		panic(fmt.Sprintf("unable to get flamingo application: %v", err))
   124  	}
   125  
   126  	testModuleInterface, err := application.ConfigArea().Injector.GetInstance(new(testModule))
   127  	testModule := testModuleInterface.(*testModule)
   128  	if err != nil {
   129  		panic("unable to get testModule in flamingo execution area")
   130  	}
   131  	listenAndServeQuited := make(chan struct{})
   132  	port, err := testModule.startServer(listenAndServeQuited)
   133  	if err != nil {
   134  		panic(err)
   135  	}
   136  
   137  	time.Sleep(1 * time.Second)
   138  
   139  	return BootupInfo{
   140  		func() {
   141  			testModule.shutdownServer()
   142  		},
   143  		application,
   144  		"localhost:" + port,
   145  		listenAndServeQuited,
   146  	}
   147  }
   148  
   149  // NewHTTPExpectWithCookies returns a new Expect object without printer with preset cookies to the base URL
   150  func NewHTTPExpectWithCookies(testingTB httpexpect.TestingTB, baseURL string, cookies map[string]string) *httpexpect.Expect {
   151  	cookieJar := httpexpect.NewCookieJar()
   152  	parse, err := url.Parse(baseURL)
   153  	if err != nil {
   154  		testingTB.Errorf(err.Error())
   155  	}
   156  	theCookies := make([]*http.Cookie, 0, len(cookies))
   157  	for key, value := range cookies {
   158  		theCookies = append(theCookies, &http.Cookie{Name: key, Value: value})
   159  	}
   160  
   161  	cookieJar.SetCookies(parse, theCookies)
   162  
   163  	return httpexpect.WithConfig(httpexpect.Config{
   164  		BaseURL: baseURL,
   165  		Client: &http.Client{
   166  			Jar: cookieJar,
   167  		},
   168  		Reporter: httpexpect.NewAssertReporter(testingTB),
   169  		Printers: nil,
   170  	})
   171  }
   172  
   173  // NewHTTPExpect returns a new Expect object without printer
   174  func NewHTTPExpect(tb httpexpect.TestingTB, baseURL string) *httpexpect.Expect {
   175  	return NewHTTPExpectWithCookies(tb, baseURL, nil)
   176  }