package httptest import ( "crypto/tls" "net/http" "net/http/httptest" "testing" "github.com/kataras/iris/v12" "github.com/kataras/iris/v12/context" "github.com/kataras/iris/v12/core/router" "github.com/kataras/iris/v12/i18n" "github.com/iris-contrib/httpexpect/v2" ) type ( // OptionSetter sets a configuration field to the configuration OptionSetter interface { // Set receives a pointer to the Configuration type and does the job of filling it Set(c *Configuration) } // OptionSet implements the OptionSetter OptionSet func(c *Configuration) ) // Set is the func which makes the OptionSet an OptionSetter, this is used mostly func (o OptionSet) Set(c *Configuration) { o(c) } // Configuration httptest configuration type Configuration struct { // URL the base url. // Defaults to empty string "". URL string // Debug if true then debug messages from the httpexpect will be shown when a test runs // Defaults to false. Debug bool // LogLevel sets the application's log level. // Defaults to "disable" when testing. LogLevel string // If true then the underline httpexpect report will be acquired by the NewRequireReporter // call instead of the default NewAssertReporter. // Defaults to false. Strict bool // Note: if more reports are available in the future then add a Reporter interface as a field. } // Set implements the OptionSetter for the Configuration itself func (c Configuration) Set(main *Configuration) { main.URL = c.URL main.Debug = c.Debug if c.LogLevel != "" { main.LogLevel = c.LogLevel } main.Strict = c.Strict } var ( // URL if set then it sets the httptest's BaseURL. // Defaults to empty string "". URL = func(schemeAndHost string) OptionSet { return func(c *Configuration) { c.URL = schemeAndHost } } // Debug if true then debug messages from the httpexpect will be shown when a test runs // Defaults to false. Debug = func(val bool) OptionSet { return func(c *Configuration) { c.Debug = val } } // LogLevel sets the application's log level. // Defaults to disabled when testing. LogLevel = func(level string) OptionSet { return func(c *Configuration) { c.LogLevel = level } } // Strict sets the Strict configuration field to "val". // Applies the NewRequireReporter instead of the default one. // Use this if you want the test to fail on first error, before all checks have been done. Strict = func(val bool) OptionSet { return func(c *Configuration) { c.Strict = val } } ) // DefaultConfiguration returns the default configuration for the httptest. func DefaultConfiguration() *Configuration { return &Configuration{URL: "", Debug: false, LogLevel: "disable"} } // New Prepares and returns a new test framework based on the "app". // Usage: // httptest.New(t, app) // With options: // httptest.New(t, app, httptest.URL(...), httptest.Debug(true), httptest.LogLevel("debug"), httptest.Strict(true)) // // Example at: https://github.com/kataras/iris/tree/master/_examples/testing/httptest. func New(t *testing.T, app *iris.Application, setters ...OptionSetter) *httpexpect.Expect { conf := DefaultConfiguration() for _, setter := range setters { setter.Set(conf) } // set the logger or disable it (default). app.Logger().SetLevel(conf.LogLevel) if err := app.Build(); err != nil { if conf.LogLevel != "disable" { app.Logger().Println(err.Error()) return nil } } var reporter httpexpect.Reporter if conf.Strict { reporter = httpexpect.NewRequireReporter(t) } else { reporter = httpexpect.NewAssertReporter(t) } testConfiguration := httpexpect.Config{ BaseURL: conf.URL, Client: &http.Client{ Transport: httpexpect.NewBinder(app), Jar: httpexpect.NewJar(), }, Reporter: reporter, } if conf.Debug { testConfiguration.Printers = []httpexpect.Printer{ httpexpect.NewDebugPrinter(t, true), } } return httpexpect.WithConfig(testConfiguration) } // NewInsecure same as New but receives a single host instead of the whole framework. // Useful for testing running TLS servers. func NewInsecure(t *testing.T, setters ...OptionSetter) *httpexpect.Expect { conf := DefaultConfiguration() for _, setter := range setters { setter.Set(conf) } transport := &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // lint:ignore } testConfiguration := httpexpect.Config{ BaseURL: conf.URL, Client: &http.Client{ Transport: transport, Jar: httpexpect.NewJar(), }, Reporter: httpexpect.NewAssertReporter(t), } if conf.Debug { testConfiguration.Printers = []httpexpect.Printer{ httpexpect.NewDebugPrinter(t, true), } } return httpexpect.WithConfig(testConfiguration) } // Aliases for "net/http/httptest" package. See `Do` package-level function. var ( NewRecorder = httptest.NewRecorder NewRequest = httptest.NewRequest ) // Do is a simple helper which can be used to test handlers individually // with the "net/http/httptest" package. // This package contains aliases for `NewRequest` and `NewRecorder` too. // // For a more efficient testing please use the `New` function instead. func Do(w http.ResponseWriter, r *http.Request, handler iris.Handler, irisConfigurators ...iris.Configurator) { app := new(iris.Application) app.I18n = i18n.New() app.Configure(iris.WithConfiguration(iris.DefaultConfiguration()), iris.WithLogLevel("disable")) app.Configure(irisConfigurators...) app.HTTPErrorHandler = router.NewDefaultHandler(app.ConfigurationReadOnly(), app.Logger()) app.ContextPool = context.New(func() interface{} { return context.NewContext(app) }) ctx := app.ContextPool.Acquire(w, r) handler(ctx) app.ContextPool.Release(ctx) }