Documentation ¶
Index ¶
- Variables
- func AddMacro(name string, macro interface{})
- func DisableJWS()
- func EnableContextDumps()
- func ExecuteMacro(name string, params []string) (string, error)
- func JWSStatus() string
- func NewDefaultPermissionGroup(tc TestCase) permissions.Group
- func NewPermissionGroup(tc TestCase) permissions.Group
- type Code
- type Component
- type ConditionEnum
- type Conditionality
- type ConditionalityChecker
- type Context
- func (c *Context) Delete(delKey string)
- func (c *Context) DumpContext(text ...string)
- func (c Context) Get(key string) (interface{}, bool)
- func (c Context) GetBool(key string) (bool, error)
- func (c Context) GetString(key string) (string, error)
- func (c Context) GetStringSlice(key string) ([]string, error)
- func (c *Context) GetStrings(text ...string) (map[string]string, error)
- func (c *Context) IsSet(key string) bool
- func (c Context) Put(key string, value interface{})
- func (c Context) PutContext(ctx *Context)
- func (c Context) PutMap(mymap map[string]string)
- func (c Context) PutString(key string, value string)
- func (c Context) PutStringSlice(key string, values []string)
- type ContextAccessor
- type Expect
- type Input
- func (i *Input) AppErr(msg string) error
- func (i *Input) AppMsg(msg string) string
- func (i *Input) Clone() Input
- func (i *Input) CreateRequest(tc *TestCase, ctx *Context) (*resty.Request, error)
- func (i *Input) GenerateRequestToken(ctx *Context) (string, error)
- func (i *Input) SetFormField(key, value string)
- func (i *Input) SetHeader(key, value string)
- func (i *Input) String() string
- type Manifest
- type Match
- func (m *Match) AppErr(msg string) error
- func (m *Match) AppMsg(msg string) string
- func (m *Match) Check(tc *TestCase) (bool, error)
- func (m *Match) Clone() Match
- func (m *Match) GetType() MatchType
- func (m *Match) ProcessReplacementFields(ctx *Context)
- func (m *Match) PutValue(tc *TestCase, ctx *Context) bool
- func (m *Match) String() string
- type MatchType
- type NamedPermission
- type NamedPermissions
- type ResourceAccountID
- type ResourceIDs
- type ResourceStatementID
- type Rule
- type SpecConsentRequirements
- type Specification
- type TestCase
- func (t *TestCase) AppEntry(msg string) string
- func (t *TestCase) AppErr(msg string) error
- func (t *TestCase) AppExit(msg string) string
- func (t *TestCase) AppMsg(msg string) string
- func (t *TestCase) ApplyContext(rulectx *Context)
- func (t *TestCase) ApplyExpects(res *resty.Response, rulectx *Context) (bool, []error)
- func (t *TestCase) ApplyInput(rulectx *Context) (*resty.Request, error)
- func (t *TestCase) Clone() TestCase
- func (t *TestCase) InjectBearerToken(token string)
- func (t *TestCase) Prepare(ctx *Context) (*resty.Request, error)
- func (t *TestCase) ProcessReplacementFields(ctx *Context, showReplacementErrors bool)
- func (t *TestCase) String() string
- func (t *TestCase) Validate(resp *resty.Response, ctx *Context) (bool, []error)
Constants ¶
This section is empty.
Variables ¶
var ErrNotFound = errors.New("error key not found")
Functions ¶
func AddMacro ¶ added in v1.6.0
func AddMacro(name string, macro interface{})
AddMacro inserts the provided macro in the map where they are held. It is not expected to be called concurrently.
func EnableContextDumps ¶ added in v1.1.18
func EnableContextDumps()
func ExecuteMacro ¶ added in v1.1.16
ExecuteMacro calls a macro by `name`, with parameters to be passed using `params`. `params` is a collection of strings that get passed as is. Type assertions will need be performed in the macro implementation.
func NewDefaultPermissionGroup ¶
func NewDefaultPermissionGroup(tc TestCase) permissions.Group
func NewPermissionGroup ¶
func NewPermissionGroup(tc TestCase) permissions.Group
NewPermissionGroup returns a list of Code objects associated with a testcase
Types ¶
type Component ¶
type Component struct { ID string `json:"@id,omitempty"` // JSONLD ID Reference Name string `json:"name,omitempty"` // Name Description string `json:"description,omitempty"` // Purpose of the testcase in simple words Documentation string `json:"documentation,omitempty"` // What input parameters do, what output parameters are InputParameters map[string]string `json:"inputParameters,omitempty"` // input parameters OutputParameters map[string]string `json:"outputParameters,omitempty"` // output parameters Tests []TestCase `json:"testcases,omitempty"` // TestCase to be run as part of this custom test Execution []string `json:"execution,omitempty"` Components []string `json:"components,omitempty"` }
Component - a reusable test case building block
func LoadComponent ¶
LoadComponent - Utility to load Manifest Data Model containing all Rules, Tests and Conditions
func (*Component) ProcessReplacementFields ¶
ProcessReplacementFields - performance context/testcase parameter substitution on component test cases before they are run
func (*Component) ValidateParameters ¶
ValidateParameters - check that the components required input and output parameters are present in the supplied context
type ConditionEnum ¶
type ConditionEnum int
ConditionEnum models endpoint conditionality based on: Account and Transaction API Specification - v3.1 - Section 4 Endpoints https://openbanking.atlassian.net/wiki/spaces/DZ/pages/937820271/Account+and+Transaction+API+Specification+-+v3.1#AccountandTransactionAPISpecification-v3.1-Endpoints Also see "Categorisation of Implementation Requirements" section of the following document https://openbanking.atlassian.net/wiki/spaces/DZ/pages/937656404/Read+Write+Data+API+Specification+-+v3.1#Read/WriteDataAPISpecification-v3.1-CategorisationofImplementationRequirements
const ( // Mandatory - required Mandatory ConditionEnum = iota // Conditional on a regulatory requirement Conditional // Optional at the implementors discretion Optional // UndefinedCondition - UndefinedCondition )
func GetConditionality ¶
func GetConditionality(method, endpoint, specification string) (ConditionEnum, error)
GetConditionality - returns and indicator in the following for of the method/endpoint conditionality model.Mandatory - endpoint is Mandatory model.Conditional - endpoint is conditional model.Optional - endpoint is optional model.UndefineCondition - we don't recognise the endpoint
type Conditionality ¶
type Conditionality struct { Condition ConditionEnum `json:"condition,omitempty"` Method string `json:"method,omitempty"` Endpoint string `json:"endpoint,omitempty"` }
Conditionality - capture the conditionality of a method/endpoint
func GetEndpointConditionality ¶
func GetEndpointConditionality(specification string) []Conditionality
GetEndpointConditionality - get a clone of `endpointConditionality` array for given specification identifier
type ConditionalityChecker ¶
type ConditionalityChecker interface { IsPresent(method, endpoint string, specification string) (bool, error) IsOptional(method, endpoint string, specification string) (bool, error) IsMandatory(method, endpoint string, specification string) (bool, error) IsConditional(method, endpoint string, specification string) (bool, error) MissingMandatory(endpoints []Input, specification string) ([]Input, error) }
ConditionalityChecker - interface to provide loose coupling between endpoint conditionality checks and invoking code
func NewConditionalityChecker ¶
func NewConditionalityChecker() ConditionalityChecker
NewConditionalityChecker - returns implementation of ConditionalityChecker interface for checking endpoint conditionality
type Context ¶
type Context map[string]interface{}
Context is intended to handle two types of object and make them available to various parts of the suite including testcases. The first set are objects created as a result of the discovery phase, which capture discovery model information like endpoints and conditional implementation indicators. The other set of data is information passed between a sequence of test cases, for example AccountId - extracted from the output of one testcase (/Accounts) and fed in as part of the input of another testcase for example (/Accounts/{AccountId}/transactions}
func (*Context) DumpContext ¶
DumpContext - send the contents of a context to a logger
func (Context) Get ¶
Get the key form the Context map - currently assumes value converts easily to a string!
func (Context) GetStringSlice ¶
GetStringSlice gets a slice of string from context
func (*Context) GetStrings ¶ added in v1.1.16
GetStrings - given a list of strings, returns a map of the strings values from context
func (*Context) IsSet ¶ added in v1.1.16
IsSet returns true if the key exists and is not set to zero value (nil or empty string)
func (Context) PutContext ¶
PutContext - puts another context into this one
func (Context) PutString ¶
PutString Put a value indexed by 'key' into the context. The value can be any type
func (Context) PutStringSlice ¶
PutStringSlice puts a slice of strings into context
type ContextAccessor ¶
type ContextAccessor struct { Context *Context `json:"-"` Matches []Match `json:"matches,omitempty"` }
ContextAccessor - Manages access to matches for Put and Get value operations on a context
func (*ContextAccessor) AppErr ¶
func (c *ContextAccessor) AppErr(msg string) error
AppErr - application level trace error msg
func (*ContextAccessor) AppMsg ¶
func (c *ContextAccessor) AppMsg(msg string) string
AppMsg - application level trace
func (*ContextAccessor) PutValues ¶
func (c *ContextAccessor) PutValues(tc *TestCase, ctx *Context) error
PutValues is used by the 'contextPut' directive and essentially collects a set of matches whose purpose is To select values to put in a context. All the matches in this section must have a name (of the target context variable), a description (so if things go wrong we can accurately report) and an operation which results in the a selection which is copied into the context variable Note: the initial interation of this will just implement the JSON pattern/field matcher
type Expect ¶
type Expect struct { StatusCode int `json:"status-code,omitempty"` // Http response code SchemaValidation bool `json:"schema-validation,omitempty"` // Flag to indicate if we need schema validation - // provides the ability to switch off schema validation Matches []Match `json:"matches,omitempty"` // An array of zero or more match items which must be 'passed' for the testcase to succeed ContextPut ContextAccessor `json:"contextPut,omitempty"` // allows storing of test response fragments in context variables }
Expect defines a structure for expressing testcase result expectations.
type Input ¶
type Input struct { Method string `json:"method,omitempty"` // http Method that this test case uses Endpoint string `json:"endpoint,omitempty"` // resource endpoint where the http object needs to be sent to get a response Headers map[string]string `json:"headers,omitempty"` // Allows for provision of specific http headers RemoveHeaders []string `json:"removeheaders,omitempty"` // Allows for removing specific http headers RemoveClaims []string `json:"removeClaims,omitempty"` // Allows for removing specific signature claims FormData map[string]string `json:"formData,omitempty"` // Allow for provision of http form data QueryParameters map[string]string `json:"queryParameters,omitempty"` // Allow for provision of http URL query parameters RequestBody string `json:"bodyData,omitempty"` // Optional request body raw data Generation map[string]string `json:"generation,omitempty"` // Allows for different ways of generating testcases Claims map[string]string `json:"claims,omitempty"` // collects claims for input strategies that require them JwsSig bool `json:"jws,omitempty"` // controls inclusion of x-jws-signature header IdempotencyKey bool `json:"idempotency,omitempty"` // specifices the inclusion of x-idempotency-key in the request }
Input defines the content of the http request object used to execute the test case Input is built up typically from the openapi/swagger definition of the method/endpoint for a particular specification. Additional properties/fields/headers can be added or change in order to setup the http request object of the specific test case. Once setup correctly,the testcase gives the http request object to the parent Rule which determine how to execute the requestion object. On execution an http response object is received and passed back to the testcase for validation using the Expects object.
func (*Input) CreateRequest ¶
CreateRequest is the main Input work horse which examines the various Input parameters and generates an http.Request object which represents the request
func (*Input) GenerateRequestToken ¶ added in v1.1.6
func (*Input) SetFormField ¶ added in v1.1.0
SetFormField - sets a field in the form
type Manifest ¶
type Manifest struct { Context string `json:"@context"` // JSONLD contest reference ID string `json:"@id"` // JSONLD ID reference Type string `json:"@type"` // JSONLD Type reference Name string `json:"name"` // Name of the manifest Description string `json:"description"` // Description of the Manifest and what it contains BaseIri string `json:"baseIri"` // Base Iri Sections []Context `json:"section_contexts"` // Section specific contexts Rules []Rule `json:"rules"` // All the rules in the Manifest }
Manifest is the high level container for test suite definition It contains a list of all the rules required to be passed for conformance testing Each rule can have multiple testcases which contribute to testing that particular rule So essentially Manifest is a container
type Match ¶
type Match struct { MatchType MatchType `json:"match_type,omitempty"` // Type of Match we're doing Description string `json:"description,omitempty"` // Description of the purpose of the match ContextName string `json:"name,omitempty"` // Context variable name Header string `json:"header,omitempty"` // Header value to examine HeaderPresent string `json:"header-present,omitempty"` // Header existence check Regex string `json:"regex,omitempty"` // Regular expression to be used JSON string `json:"json,omitempty"` // Json expression to be used Value string `json:"value,omitempty"` // Value to match against (string) Numeric int64 `json:"numeric,omitempty"` // Value to match against - numeric Count int64 `json:"count,omitempty"` // Cont for JSON array match purposes BodyLength *int64 `json:"body-length,omitempty"` // Body payload length for matching ReplaceEndpoint string `json:"replaceInEndpoint,omitempty"` // allows substitution of resourceIds Authorisation string `json:"authorisation,omitempty"` // allows capturing of bearer tokens Result string `json:"result,omitempty"` // capturing match values Custom string `json:"custom,omitempty"` // specifies custom matching routine }
Match defines various types of response payload pattern and field checking. Match forms the basis for response validation outside of basic swagger/openapi schema validation Match is also used as the basis for field extraction and replacement which enable parameter passing between tests via the context. Match encapsulates a conditional statement that must 'match' in order to succeed. Matches can - - match a specified header field value for exact match - match a specified header field value using a regular expression - check that a specified header field exists in the response - check that a response body matches a regular expression - check that a response body has a particular json field present using json matching - check that a response body has a specific number of specified json array fields - check that a response body has a specific value of a specified json field - check that a response body has a specific json field and that the specific json field matches a regular expression - check that a response body is a specified length - allow for replacement of endpoint text ... e.g. {AccountId} - Authorization: allow for manipulation of Bearer tokens in http headers - Result: allow for capturing of match values for further processing - like putting into a context
func (*Match) Check ¶
Check a match function - figures out which match type we have and calls the appropriate match checking function
func (*Match) Clone ¶
Clone duplicates a Match into a separate independent object TODO: consider cloning the contextPut Omit bodylength for now...
func (*Match) ProcessReplacementFields ¶
ProcessReplacementFields allows parameter replacement within match string fields
type NamedPermission ¶
type NamedPermission struct { Name string `json:"name"` CodeSet permissions.CodeSetResult `json:"codeSet"` ConsentUrl string `json:"consentUrl"` }
type NamedPermissions ¶
type NamedPermissions []NamedPermission
func (*NamedPermissions) Add ¶
func (t *NamedPermissions) Add(token NamedPermission)
type ResourceAccountID ¶
type ResourceAccountID struct {
AccountID string `json:"account_id"`
}
type ResourceIDs ¶
type ResourceIDs struct { AccountIDs []ResourceAccountID `json:"account_ids"` StatementIDs []ResourceStatementID `json:"statement_ids"` }
type ResourceStatementID ¶
type ResourceStatementID struct {
StatementID string `json:"statement_id"`
}
type Rule ¶
type Rule struct { ID string `json:"@id"` // JSONLD ID reference Type []string `json:"@type,omitempty"` // JSONLD type reference Name string `json:"name"` // A short meaningful name for this rule Purpose string `json:"purpose"` // The purpose of this rule Specref string `json:"specref"` // Description of area of spec/name/version/section under test Speclocation string `json:"speclocation"` // specific http reference to location in spec under test covered by this rule Tests [][]TestCase `json:"tests"` // Tests - allows for many testcases - array of arrays - to be associated with this rule }
Rule - Define a specific location within a specification that is being tested Rule also identifies all the tests that must be passed in order to show that the rule implementation in conformant with the specific section in the referenced specification
type SpecConsentRequirements ¶
type SpecConsentRequirements struct { Identifier string `json:"specIdentifier"` NamedPermissions NamedPermissions `json:"namedPermissions"` }
func NewSpecConsentRequirements ¶
func NewSpecConsentRequirements(nameGenerator names.Generator, result permissions.CodeSetResultSet, specId string) SpecConsentRequirements
type Specification ¶
type Specification struct { Identifier string Name string // URL of confluence specifications file. URL *url.URL // Version of the specifications Version string // URL of OpenAPI/Swagger specifications file. SchemaVersion *url.URL }
Specification - Represents OB API specification. Fields are from the APIReference JSON-LD schema, see: https://schema.org/APIReference
func SpecificationFromSchemaVersion ¶
func SpecificationFromSchemaVersion(schemaVersion string) (Specification, error)
SpecificationFromSchemaVersion - returns specification struct for given schema version URL, or nil when there is no match.
func Specifications ¶
func Specifications() []Specification
Specifications - get a clone of the `specifications` array.
type TestCase ¶
type TestCase struct { ID string `json:"@id,omitempty"` // JSONLD ID Reference Type []string `json:"@type,omitempty"` // JSONLD type array Name string `json:"name,omitempty"` // Name Detail string `json:"detail,omitempty"` // Detailed description of the test case RefURI string `json:"refURI,omitempty"` // Reference URI for the test case Purpose string `json:"purpose,omitempty"` // Purpose of the testcase in simple words Input Input `json:"input,omitempty"` // Input Object Context Context `json:"context,omitempty"` // Local Context Object Expect Expect `json:"expect,omitempty"` // Expected object ExpectOneOf []Expect `json:"expect_one_of,omitempty"` // Slice of possible expected objects ParentRule *Rule `json:"-"` // Allows accessing parent Rule Request *resty.Request `json:"-"` // The request that's been generated in order to call the endpoint Header http.Header `json:"-"` // ResponseHeader Body string `json:"-"` // ResponseBody Bearer string `json:"bearer,omitempty"` // Bear token if presented DoNotCallEndpoint bool `json:"do_not_call_endpoint,omitempty"` // If we should not call the endpoint, see `components/PSUConsentProviderComponent.json` APIName string `json:"apiName"` APIVersion string `json:"apiVersion"` Validator schema.Validator `json:"-"` // Swagger schema validator ValidateSignature bool `json:"validateSignature,omitempty"` StatusCode string `json:"statusCode,omitempty"` }
TestCase defines a test that will be run and needs to be passed as part of the conformance suite in order to determine implementation conformance to a specification. Testcase have three major sections Input:
Defines the inputs that are required by the testcase. This effectively involves preparing the http request object
Context:
Provides a link between Discovery information and the testcase
Expects:
Examines the http response to the testcase Input in order to determine if the expected conditions existing in the response and therefore the testcase has passed
func LoadTestCaseFromJSONFile ¶ added in v1.1.0
LoadTestCaseFromJSONFile a single testcase from a json file
func (*TestCase) ApplyContext ¶
ApplyContext - at the end of ApplyInputs on the testcase - we have an initial http request object ApplyContext, applies context parameters to the http object. Context parameter typically involve variables that originated in discovery The functionality of ApplyContext will grow significantly over time.
func (*TestCase) ApplyExpects ¶
ApplyExpects runs the Expects section of the testcase to evaluate if the response from the system under test passes or fails The Expects section of a testcase can contain multiple conditions that need to be met to pass a testcase When a test fails, ApplyExpects is responsible for reporting back information about the failure, why it occurred, where it occurred etc.
The ApplyExpect section is also responsible for running and contextPut clauses. contextPuts are responsible for updated context variables with values selected from the test case response contextPuts will only be executed if the ApplyExpects standards match tests pass if any of the ApplyExpects match tests fail - ApplyExpects returns false and contextPuts aren't executed
func (*TestCase) ApplyInput ¶
ApplyInput - creates an HTTP request for this test case The reason why we're doing this is that a testcase behaves like an http object It produces an http.Request - which can be sent to a server It consumes an http.Response - which it uses to validate the response against "Expects" TestCase lifecycle:
Create a Testcase Object Create / retrieve the http request object Apply context information to the request object Rule - manages passing the request object from the testcase to an appropriate endpoint handler (like the proxy) Rule - receives http response from endpoint and provides it back to testcase Testcase evaluates the http response object using its 'Expects' clause Testcase passes or fails depending on the 'Expects' outcome
func (*TestCase) InjectBearerToken ¶
InjectBearerToken injects a bear token header into the testcase, token can either be the actual bearer token or a parameter starting with '$'
func (*TestCase) Prepare ¶
Prepare a Testcase for execution at and endpoint, results in a standard http request that encapsulates the testcase request as defined in the test case object with any context inputs/replacements etc applied
func (*TestCase) ProcessReplacementFields ¶
ProcessReplacementFields prefixed by '$' in the testcase Input and Context sections Call to pre-process custom test cases from discovery model
func (*TestCase) Validate ¶
Validate takes the http response that results as a consequence of sending the testcase http request to the endpoint implementation. Validate is responsible for checking the http status code and running the set of 'Matches' within the 'Expect' object, to determine if all the match conditions are met - which would mean the validation passed. The context object is passed as part of the validation as its allows the match clauses to examine the request object and 'push' response variables into the context object for use in downstream test cases which are potentially part of this testcase sequence returns true - validation successful
false - validation unsuccessful error - adds detail to validation failure NOTE: Validate will only return false if a check fails - no checks = true