github.com/blend/go-sdk@v1.20220411.3/web/mock.go (about)

     1  /*
     2  
     3  Copyright (c) 2022 - Present. Blend Labs, Inc. All rights reserved
     4  Use of this source code is governed by a MIT license that can be found in the LICENSE file.
     5  
     6  */
     7  
     8  package web
     9  
    10  import (
    11  	"bytes"
    12  	"context"
    13  	"encoding/json"
    14  	"io"
    15  	"net/http"
    16  	"net/http/httptest"
    17  	"net/url"
    18  
    19  	"github.com/blend/go-sdk/r2"
    20  	"github.com/blend/go-sdk/webutil"
    21  )
    22  
    23  // Mock sends a mock request to an app.
    24  // It will reset the app Server, Listener, and will set the request host to the listener address
    25  // for a randomized local listener.
    26  func Mock(app *App, req *http.Request, options ...r2.Option) *MockResult {
    27  	var err error
    28  	result := &MockResult{
    29  		App: app,
    30  		Request: &r2.Request{
    31  			Request: req,
    32  		},
    33  	}
    34  	for _, option := range options {
    35  		if err = option(result.Request); err != nil {
    36  			result.Err = err
    37  			return result
    38  		}
    39  	}
    40  
    41  	if err := app.StartupTasks(); err != nil {
    42  		result.Err = err
    43  		return result
    44  	}
    45  
    46  	if result.Request.Request.URL == nil {
    47  		result.Request.Request.URL = &url.URL{}
    48  	}
    49  
    50  	result.Server = httptest.NewUnstartedServer(app)
    51  	result.Server.Config.BaseContext = app.BaseContext
    52  	result.Server.Start()
    53  	result.Request.Closer = result.Close
    54  
    55  	parsedServerURL := webutil.MustParseURL(result.Server.URL)
    56  	result.Request.Request.URL.Scheme = parsedServerURL.Scheme
    57  	result.Request.Request.URL.Host = parsedServerURL.Host
    58  
    59  	return result
    60  }
    61  
    62  // MockMethod sends a mock request with a given method to an app.
    63  // You should use request options to set the body of the request if it's a post or put etc.
    64  func MockMethod(app *App, method, path string, options ...r2.Option) *MockResult {
    65  	req := &http.Request{
    66  		Method: method,
    67  		URL: &url.URL{
    68  			Path: path,
    69  		},
    70  	}
    71  	return Mock(app, req, options...)
    72  }
    73  
    74  // MockGet sends a mock get request to an app.
    75  func MockGet(app *App, path string, options ...r2.Option) *MockResult {
    76  	req := &http.Request{
    77  		Method: "GET",
    78  		URL: &url.URL{
    79  			Path: path,
    80  		},
    81  	}
    82  	return Mock(app, req, options...)
    83  }
    84  
    85  // MockPost sends a mock post request to an app.
    86  func MockPost(app *App, path string, body io.ReadCloser, options ...r2.Option) *MockResult {
    87  	req := &http.Request{
    88  		Method: "POST",
    89  		Body:   body,
    90  		URL: &url.URL{
    91  			Path: path,
    92  		},
    93  	}
    94  	return Mock(app, req, options...)
    95  }
    96  
    97  // MockPostJSON sends a mock post request with a json body to an app.
    98  func MockPostJSON(app *App, path string, body interface{}, options ...r2.Option) *MockResult {
    99  	contents, _ := json.Marshal(body)
   100  	req := &http.Request{
   101  		Method: "POST",
   102  		Body:   io.NopCloser(bytes.NewReader(contents)),
   103  		URL: &url.URL{
   104  			Path: path,
   105  		},
   106  	}
   107  	return Mock(app, req, options...)
   108  }
   109  
   110  // MockResult is a result of a mocked request.
   111  type MockResult struct {
   112  	*r2.Request
   113  	App    *App
   114  	Server *httptest.Server
   115  }
   116  
   117  // Close stops the app.
   118  func (mr *MockResult) Close() error {
   119  	mr.Server.Close()
   120  	return nil
   121  }
   122  
   123  // MockCtx returns a new mock ctx.
   124  // It is intended to be used in testing.
   125  func MockCtx(method, path string, options ...CtxOption) *Ctx {
   126  	return MockCtxWithBuffer(method, path, new(bytes.Buffer), options...)
   127  }
   128  
   129  // MockCtxWithBuffer returns a new mock ctx.
   130  // It is intended to be used in testing.
   131  func MockCtxWithBuffer(method, path string, buf io.Writer, options ...CtxOption) *Ctx {
   132  	return NewCtx(
   133  		webutil.NewMockResponse(buf),
   134  		webutil.NewMockRequest(method, path),
   135  		append(
   136  			[]CtxOption{
   137  				OptCtxApp(new(App)),
   138  				OptCtxDefaultProvider(Text),
   139  			},
   140  			options...,
   141  		)...,
   142  	)
   143  }
   144  
   145  // MockSimulateLogin simulates a user login for a given app as mocked request params (i.e. r2 options).
   146  //
   147  // This requires an auth manager to be set on the app.
   148  func MockSimulateLogin(ctx context.Context, app *App, userID string, opts ...r2.Option) []r2.Option {
   149  	sessionID := NewSessionID()
   150  	session := NewSession(userID, sessionID)
   151  	if app.Auth.PersistHandler != nil {
   152  		_ = app.Auth.PersistHandler(ctx, session)
   153  	}
   154  	return append([]r2.Option{
   155  		r2.OptCookieValue(app.Auth.CookieDefaults.Name, sessionID),
   156  	}, opts...)
   157  }