Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
ac7980f
ADD GO DOC COMMENTS FOR TESTING HTTP INTERFACES
krishankumar01 Jan 2, 2026
ffa6a3f
optimise http server testing
krishankumar01 Jan 2, 2026
5472959
add custom TestingT interface
krishankumar01 Jan 2, 2026
defb3e1
add custom TestingT interface
krishankumar01 Jan 2, 2026
02ed0aa
add FailNow method in TestingT interface
krishankumar01 Jan 5, 2026
8f71627
add FailNow method in TestingT interface
krishankumar01 Jan 5, 2026
3ffe766
add new method for http client testing
krishankumar01 Jan 5, 2026
f79251c
Merge branch 'master' into kkumar-gcc/#841-2
krishankumar01 Jan 5, 2026
a5f4f9c
optimize testing methods
krishankumar01 Jan 8, 2026
6323b5b
optimize testing methods
krishankumar01 Jan 8, 2026
d8eefc9
use custom type for clientName
krishankumar01 Jan 8, 2026
49c4177
remove unnecessary comments from interfaces
krishankumar01 Jan 10, 2026
0199af9
optimise fake_transport
krishankumar01 Jan 10, 2026
9488332
use optimized fake_transport in factory
krishankumar01 Jan 10, 2026
4a8caf4
add test cases for response factory and sequence
krishankumar01 Jan 11, 2026
6bcb394
add test cases for new methods of factory
krishankumar01 Jan 11, 2026
bae176a
use # to distinguish clientName and path
krishankumar01 Jan 11, 2026
4c4f74a
optimise factory
krishankumar01 Jan 11, 2026
8458fc9
return body read error in hydrate
krishankumar01 Jan 11, 2026
dac72c9
optimise AllowStrayRequests and PreventStrayRequests
krishankumar01 Jan 11, 2026
1da61d1
directly resolve using clients instead of calling embedded field
krishankumar01 Jan 11, 2026
b8a9db0
rename interfaces and add go doc comments
krishankumar01 Jan 13, 2026
25ee140
optimise factory
krishankumar01 Jan 13, 2026
77384b2
use snapshotting in FakeSequence to fix body draining
krishankumar01 Jan 14, 2026
48f5675
fix non-deterministic mock matching for wildcard patterns
krishankumar01 Jan 14, 2026
999088d
update FakeResponse to use http.Header and unified make helper
krishankumar01 Jan 14, 2026
911bd11
optimise fake_rule
krishankumar01 Jan 15, 2026
bee41bf
add test for Factory.Reset
krishankumar01 Jan 17, 2026
e832b93
re-order the input parameter of FakeResponse methods
krishankumar01 Jan 18, 2026
593e3ef
optimise test cases
krishankumar01 Jan 18, 2026
4b35723
change code to status
krishankumar01 Jan 19, 2026
50411ac
chore: update mocks
krishankumar01 Jan 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 34 additions & 17 deletions contracts/http/client/factory.go
Original file line number Diff line number Diff line change
@@ -1,24 +1,41 @@
package client

type Factory interface {
// Request embeds the HTTP verb methods (Get, Post, etc.) and configuration methods (WithHeader, etc.).
//
// This embedding allows you to use the default client directly without calling Client().
//
// Example:
// // Uses the 'default' client defined in config/http.go
// facades.Http().Get("/users")
// Request embeds the Request interface, allowing direct usage like Http.Get().
Request

// Client switches the context to a specific client configuration.
//
// It returns a Request builder pre-configured with the specific client's settings
// (such as BaseURL, Timeout, and Headers) defined in your configuration file.
//
// If no name is provided, the default client is returned.
//
// Example:
// // Switch to the 'github' client and make a request
// facades.Http().Client("github").Post("/charges", data)
// AllowStrayRequests permits specific URL patterns to bypass the mock firewall.
AllowStrayRequests(patterns []string) Factory

// AssertNotSent verifies that no request matching the given assertion was sent.
AssertNotSent(assertion func(req Request) bool) bool

// AssertNothingSent verifies that no HTTP requests were sent at all.
AssertNothingSent() bool

// AssertSent verifies that at least one request matching the given assertion was sent.
AssertSent(assertion func(req Request) bool) bool

// AssertSentCount verifies that the specific number of requests matching the criteria were sent.
AssertSentCount(count int) bool

// Client returns a new request builder.
// If name is provided, it returns the configuration for that specific client.
// If no name is provided, it returns the default client.
Client(name ...string) Request

// Fake registers the mock rules for testing.
Fake(mocks map[string]any) Factory

// PreventStrayRequests enforces that all sent requests must match a defined mock rule.
PreventStrayRequests() Factory

// Reset restores the factory to its original state, clearing all mocks.
Reset()

// Response returns a builder for creating stubbed responses.
Response() FakeResponse

// Sequence returns a builder for defining ordered mock responses.
Sequence() FakeSequence
}
23 changes: 23 additions & 0 deletions contracts/http/client/fake_response.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package client

import "net/http"

type FakeResponse interface {
// File creates a mock response using the contents of a file at the specified path.
File(status int, path string) Response

// Json creates a mock response with a JSON body and "application/json" content type.
Json(status int, obj any) Response

// Make constructs a custom mock response with the specified body, status, and headers.
Make(status int, body string, header http.Header) Response

// OK creates a generic 200 OK mock response with an empty body.
OK() Response

// Status creates a mock response with the specified status code and an empty body.
Status(status int) Response

// String creates a mock response with a raw string body.
String(status int, body string) Response
}
15 changes: 15 additions & 0 deletions contracts/http/client/fake_sequence.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package client

type FakeSequence interface {
// Push adds a specific response to the sequence.
Push(response Response, count ...int) FakeSequence

// PushStatus adds a status-only response to the sequence.
PushStatus(status int, count ...int) FakeSequence

// PushString adds a string-body response to the sequence.
PushString(status int, body string, count ...int) FakeSequence

// WhenEmpty defines the default response to return when the sequence is exhausted.
WhenEmpty(response Response) FakeSequence
}
133 changes: 87 additions & 46 deletions contracts/http/client/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,70 +7,111 @@ import (
)

type Request interface {
// Get sends a GET request to the specified URI.
Get(uri string) (Response, error)
// Post sends a POST request to the specified URI with the given body.
Post(uri string, body io.Reader) (Response, error)
// Put sends a PUT request to the specified URI with the given body.
Put(uri string, body io.Reader) (Response, error)
// Delete sends a DELETE request to the specified URI with the given body.
Delete(uri string, body io.Reader) (Response, error)
// Patch sends a PATCH request to the specified URI with the given body.
Patch(uri string, body io.Reader) (Response, error)
// Head sends a HEAD request to the specified URI.
Head(uri string) (Response, error)

// Options sends an OPTIONS request to the specified URI.
Options(uri string) (Response, error)
// Accept sets the Accept header to the specified content type.
// Accept sets the "Accept" header to the specified content type.
Accept(contentType string) Request
// AcceptJSON sets the Accept header to "application/json".

// AcceptJSON sets the "Accept" header to "application/json".
AcceptJSON() Request
// AsForm sets the Content-Type header to "application/x-www-form-urlencoded".

// AsForm sets the "Content-Type" header to "application/x-www-form-urlencoded".
AsForm() Request
// BaseUrl overrides the base URL defined in the configuration for this specific request chain.
//
// This allows you to hit a different domain than the one configured for the
// client, useful for dynamic subdomains or runtime overrides.

// BaseUrl sets the base URL for the request, overriding the configuration.
BaseUrl(url string) Request

// Body returns the raw payload of the request as a string.
Body() string

// ClientName returns the name of the client configuration used for this request.
ClientName() string

// Clone creates a deep copy of the request builder.
// This is useful if you want to reuse a base request with shared headers/tokens
// for multiple distinct API calls.
Clone() Request
// FlushHeaders clears all configured headers.

// Delete sends a DELETE request to the specified URI with the given body.
Delete(uri string, body io.Reader) (Response, error)

// FlushHeaders removes all currently configured headers from the request builder.
FlushHeaders() Request

// Get sends a GET request to the specified URI.
Get(uri string) (Response, error)

// Head sends a HEAD request to the specified URI.
Head(uri string) (Response, error)

// Header retrieves the value of a specific header key.
Header(key string) string

// Headers retrieves all headers associated with the request.
Headers() http.Header

// HttpClient returns the underlying standard library *http.Client.
// Use this for advanced scenarios like injecting the client into third-party SDKs.
HttpClient() *http.Client

// Input retrieves a specific value from the request body or query parameters.
Input(key string) any

// Method returns the HTTP verb of the request.
Method() string

// Options sends an OPTIONS request to the specified URI.
Options(uri string) (Response, error)

// Patch sends a PATCH request to the specified URI with the given body.
Patch(uri string, body io.Reader) (Response, error)

// Post sends a POST request to the specified URI with the given body.
Post(uri string, body io.Reader) (Response, error)

// Put sends a PUT request to the specified URI with the given body.
Put(uri string, body io.Reader) (Response, error)

// ReplaceHeaders replaces all existing headers with the provided map.
ReplaceHeaders(headers map[string]string) Request
// WithBasicAuth sets the Authorization header using Basic Auth.

// Url returns the full, resolved URL of the request.
Url() string

// WithBasicAuth sets the "Authorization" header using the Basic Auth standard.
WithBasicAuth(username, password string) Request

// WithContext sets the context for the request.
WithContext(ctx context.Context) Request
// WithCookies adds the provided cookies to the request.
WithCookies(cookies []*http.Cookie) Request
// WithCookie adds a single cookie to the request.

// WithCookie adds a single http.Cookie to the request.
WithCookie(cookie *http.Cookie) Request
// WithHeader sets a specific header key to the given value.

// WithCookies adds multiple http.Cookie objects to the request.
WithCookies(cookies []*http.Cookie) Request

// WithHeader adds a specific header key-value pair to the request.
WithHeader(key, value string) Request
// WithHeaders adds multiple headers to the request.
WithHeaders(map[string]string) Request
// WithQueryParameter adds a query parameter to the URL.

// WithHeaders adds multiple headers to the request from a map.
WithHeaders(headers map[string]string) Request

// WithQueryParameter adds a single query parameter to the URL.
WithQueryParameter(key, value string) Request
// WithQueryParameters adds multiple query parameters to the URL.
WithQueryParameters(map[string]string) Request
// WithQueryString parses and adds a raw query string (e.g., "foo=bar&baz=qux").

// WithQueryParameters adds multiple query parameters to the URL from a map.
WithQueryParameters(params map[string]string) Request

// WithQueryString parses a raw query string and adds it to the URL.
WithQueryString(query string) Request
// WithoutHeader removes a specific header by key.
WithoutHeader(key string) Request
// WithToken sets the Authorization header using a Bearer token.
// You can optionally specify a custom token type (e.g., "Basic") as the second argument.

// WithToken sets the "Authorization" header using a Bearer token.
WithToken(token string, ttype ...string) Request
// WithoutToken removes the Authorization header.
WithoutToken() Request
// WithUrlParameter replaces a URL parameter placeholder (e.g., "{id}") with the given value.

// WithUrlParameter replaces a URL parameter placeholder with the given value.
WithUrlParameter(key, value string) Request
// WithUrlParameters replaces multiple URL parameter placeholders.
WithUrlParameters(map[string]string) Request

// WithUrlParameters replaces multiple URL parameter placeholders with values from a map.
WithUrlParameters(params map[string]string) Request

// WithoutHeader removes a specific header from the request by key.
WithoutHeader(key string) Request

// WithoutToken removes the "Authorization" header from the request.
WithoutToken() Request
}
110 changes: 69 additions & 41 deletions contracts/http/client/response.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,65 +6,93 @@ import (
)

type Response interface {
// Bind unmarshalls the response body into the provided value.
//
// Typical usage is:
// 1. Inspect the status (e.g. via Successful(), Failed(), or Status()).
// 2. Call Bind on responses where you expect a body to decode.
//
// Bind is intended for non-streaming use and assumes it can read the
// response body. If the body has already been consumed (for example by a
// prior call to Stream() or any other code that fully reads the body),
// Bind may return an error or fail to populate the target value.
//
// Prefer Bind when you want the entire body decoded into a struct or map.
// Prefer Stream() when you need to process large bodies incrementally.
// Accepted determines if the response status code is 202 Accepted.
Accepted() bool

// BadRequest determines if the response status code is 400 Bad Request.
BadRequest() bool

// Bind unmarshalls the JSON response body into the provided value.
Bind(value any) error

// Body returns the response body as a string.
Body() (string, error)
// ClientError determines if the response status code is >= 400 and < 500.

// ClientError determines if the response status code is in the 400-499 range.
ClientError() bool

// Conflict determines if the response status code is 409 Conflict.
Conflict() bool

// Cookie retrieves a cookie by name from the response.
Cookie(name string) *http.Cookie
// Cookies returns all cookies from the response.

// Cookies returns all cookies provided by the response.
Cookies() []*http.Cookie

// Created determines if the response status code is 201 Created.
Created() bool

// Failed determines if the response status code is >= 400.
Failed() bool
// Header retrieves the first value of a given header field.

// Forbidden determines if the response status code is 403 Forbidden.
Forbidden() bool

// Found determines if the response status code is 302 Found.
Found() bool

// Header retrieves the first value of a specific header from the response.
Header(name string) string
// Headers returns all response headers.

// Headers returns all headers from the response.
Headers() http.Header
// Json returns the response body parsed as a map[string]any.

// Json returns the response body parsed as a map.
Json() (map[string]any, error)
// Redirect determines if the response status code is >= 300 and < 400.

// MovedPermanently determines if the response status code is 301 Moved Permanently.
MovedPermanently() bool

// NoContent determines if the response status code is 204 No Content.
NoContent() bool

// NotFound determines if the response status code is 404 Not Found.
NotFound() bool

// OK determines if the response status code is 200 OK.
OK() bool

// Origin returns the underlying standard library *http.Response.
Origin() *http.Response

// PaymentRequired determines if the response status code is 402 Payment Required.
PaymentRequired() bool

// Redirect determines if the response status code is in the 300-399 range.
Redirect() bool

// RequestTimeout determines if the response status code is 408 Request Timeout.
RequestTimeout() bool

// ServerError determines if the response status code is >= 500.
ServerError() bool
// Status returns the HTTP status code.

// Status returns the integer HTTP status code of the response.
Status() int

// Stream returns the underlying reader to stream the response body.
// Use this for large files to avoid loading the entire content into memory.
//
// NOTE: You are responsible for closing the returned reader.
Stream() (io.ReadCloser, error)
// Successful determines if the response status code is >= 200 and < 300.

// Successful determines if the response status code is in the 200-299 range.
Successful() bool

/* Status Code Helpers */

OK() bool // 200 OK
Created() bool // 201 Created
Accepted() bool // 202 Accepted
NoContent() bool // 204 No Content
MovedPermanently() bool // 301 Moved Permanently
Found() bool // 302 Found
BadRequest() bool // 400 Bad Request
Unauthorized() bool // 401 Unauthorized
PaymentRequired() bool // 402 Payment Required
Forbidden() bool // 403 Forbidden
NotFound() bool // 404 Not Found
RequestTimeout() bool // 408 Request Timeout
Conflict() bool // 409 Conflict
UnprocessableEntity() bool // 422 Unprocessable Entity
TooManyRequests() bool // 429 Too Many Requests
// TooManyRequests determines if the response status code is 429 Too Many Requests.
TooManyRequests() bool

// Unauthorized determines if the response status code is 401 Unauthorized.
Unauthorized() bool

// UnprocessableEntity determines if the response status code is 422 Unprocessable Entity.
UnprocessableEntity() bool
}
Loading
Loading