model

package
v0.1.0-pre-alpha Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 30, 2018 License: MIT Imports: 13 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func SpecificationIdentifierFromSchemaVersion

func SpecificationIdentifierFromSchemaVersion(schemaVersion string) (string, error)

SpecificationIdentifierFromSchemaVersion - returns specification identifier for given schema version URL, or nil when there is no match.

Types

type ConditionEnum

type ConditionEnum int

ConditionEnum models endpoint conditionality based on: Account and Transaction API Specification - v3.0 - Section 4 Endpoints https://openbanking.atlassian.net/wiki/spaces/DZ/pages/642090641/Account+and+Transaction+API+Specification+-+v3.0#AccountandTransactionAPISpecification-v3.0-Endpoints Also see "Categorisation of Implementation Requirements" section of the following document https://openbanking.atlassian.net/wiki/spaces/DZ/pages/641992418/Read+Write+Data+API+Specification+-+v3.0#Read/WriteDataAPISpecification-v3.0-CategorisationofImplementationRequirements

const (
	// Mandatory - required
	Mandatory ConditionEnum = iota
	// Conditional on a regulartory requirement
	Conditional
	// Optional at the implementors discretion
	Optional
	// UndefinedCondition -
	UndefinedCondition
)

func GetConditionality

func GetConditionality(method, endpoint string, 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 sequeuence 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) Get

func (c Context) Get(key string) interface{}

Get the key form the Context map - currently assumes value converts easily to a string!

func (Context) Put

func (c Context) Put(key string, value interface{})

Put a value indexed by 'key' into the context. The value can be any type

type ContextAccessor

type ContextAccessor struct {
	Context *Context
	Matches []Match `json:"matches,omitempty"`
}

ContextAccessor - Manages access to matches for Put and Get value operations on a context

func (*ContextAccessor) GetValues

func (c *ContextAccessor) GetValues(tc *TestCase, ctx *Context) error

GetValues - checks for match elements in the contextGet section For each valid element there need to be a ContextName which is the name of the variable in the context we're trying to retrieve Once we have retrieved a context variable, we need to know what to do with it. Current we can ReplaceEndpoint - so basically do a string replace on our testcase endpoint which for example allows us to replace {AccountId} with a real account id

func (*ContextAccessor) PutValues

func (c *ContextAccessor) PutValues(tc *TestCase, ctx *Context) (string, 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
	ContextGet ContextAccessor `json:"contextGet,omitempty"` // Allows retrieval of context variables an input parameters
}

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 particualar 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.

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 manifiest
	Description string    `json:"description"`      // Description of the Mainfest 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

func (*Manifest) String

func (m *Manifest) String() string

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 substituion of resourceIds
}

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

func (*Match) Check

func (m *Match) Check(tc *TestCase) (bool, error)

Check a match function - figures out which match type we have and calls the appropraite match checking function

func (*Match) GetType

func (m *Match) GetType() MatchType

GetType - returns the type of a match

func (*Match) GetValue

func (m *Match) GetValue(inputBuffer string) (interface{}, string)

GetValue the value from the json match along with a context variable to put it into

func (*Match) PutValue

func (m *Match) PutValue(inputBuffer string, ctx *Context) bool

PutValue puts the value from the json match along with a context variable to put it into

type MatchType

type MatchType int

MatchType enumeration

const (
	UnknownMatchType MatchType = iota
	HeaderValue
	HeaderRegex
	HeaderPresent
	BodyRegex
	BodyJSONPresent
	BodyJSONCount
	BodyJSONValue
	BodyJSONRegex
	BodyLength
)

MatchType enumeration - this will be required when we extend to more than just BodyJSONValue

type Permission

type Permission struct {
	Permission          string   `json:"permission,omitempty"`
	Endpoints           []string `json:"endpoints,omitempty"`
	Default             bool     `json:"default,omitempty"`
	RequiredPermissions []string `json:"required_permissions,omitempty"`
	Optional            []string `json:"optional,omitempty"`
}

Permission holds endpoint permission data

func GetPermissionFromName

func GetPermissionFromName(name string) Permission

GetPermissionFromName returns a permission if a matching permission name is found or and empty permission if an entry with a matching name is not found

func GetPermissionsForEndpoint

func GetPermissionsForEndpoint(endpoint string) []Permission

GetPermissionsForEndpoint returns a list of permissions that are accepted by the specified endpoint no indication of whats mandatory/optional is given, you have to examine the individual permissions returned for that information if not entries are found a permission array with zero entries is returned

type PermissionSet

type PermissionSet struct {
	// contains filtered or unexported fields
}

PermissionSet contains a collection of permission names with the intention of using this structure to determine whether specific permissions are included in the set.

func NewPermissionSet

func NewPermissionSet(name string, strPermissions []string) *PermissionSet

NewPermissionSet create a new permission set of an array of string permission names

func (*PermissionSet) Add

func (set *PermissionSet) Add(s string) bool

Add a string to a PermissionSet

func (*PermissionSet) AddPermissions

func (set *PermissionSet) AddPermissions(ss []string)

AddPermissions - adds permission strings from a slice

func (*PermissionSet) Get

func (set *PermissionSet) Get(s string) bool

Get a permission from the PermissionSet

func (*PermissionSet) GetName

func (set *PermissionSet) GetName() string

GetName returns the name associated with this permission set

func (*PermissionSet) GetPermissions

func (set *PermissionSet) GetPermissions() []string

GetPermissions returns a string array of the permissions in a permissionSet

func (*PermissionSet) IsSubset

func (set *PermissionSet) IsSubset(sub *PermissionSet) bool

IsSubset determines if the permissionSet passed in as a paramter is a subset of the target PermissionSet

func (*PermissionSet) Remove

func (set *PermissionSet) Remove(s string)

Remove a value from the PermissionSet

func (*PermissionSet) SetName

func (set *PermissionSet) SetName(s string)

SetName sets the name associated with this permission set

func (*PermissionSet) Union

func (set *PermissionSet) Union(u *PermissionSet) *PermissionSet

Union returns a new PermissionSet named "union" which is the union of the receiver and parameter permissionSets

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
	Executor     TestCaseExecutor // TestCaseExecutor interface allow different testcase execution strategies
}

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

func (*Rule) Execute

func (r *Rule) Execute(req *http.Request, tc *TestCase) (*http.Response, error)

Execute the testcase For the rule this effectively equates to sending the assembled http request from the testcase to an endpoint (typically ASPSP implemetation) and getting an http.Response The http.Request at this point will contain the fully assembled request from a testcase point of view - testcase will have likely pulled out appropriate access_tokens/permissions - rule will have the opportunited to further decorate this request before passing on

func (*Rule) GetPermissionSets

func (r *Rule) GetPermissionSets() (included, excluded []string)

GetPermissionSets returns the inclusive and exclusive permission sets required to run the tests under this rule. Initially the granulatiy of permissionSets will be set at rule level, meaning that one included set and one excluded set will cover all the testcases with a rule. In future iterations it may be desirable to have per testSequence permissionSets as this would allow a finer grained mix of negative permission testing

func (*Rule) RunTests

func (r *Rule) RunTests()

RunTests - runs all the tests for aTestRule

func (*Rule) String

func (r *Rule) String() string

type Specification

type Specification struct {
	Identifier    string `json:"identifier,omitempty" validate:"required"`
	Name          string `json:"name,omitempty" validate:"required"`
	URL           string `json:"url,omitempty" validate:"required,url"`
	Version       string `json:"version,omitempty" validate:"required"`
	SchemaVersion string `json:"schemaVersion,omitempty" validate:"required,url"`
}

Specification - Represents OB API specification. Fields are from the APIReference JSON-LD schema, see: https://schema.org/APIReference URL - URL of confluence specification file. SchemaVersion - URL of OpenAPI/Swagger specification file.

func SpecificationFromSchemaVersion

func SpecificationFromSchemaVersion(schemaVersion string) (Specification, error)

SpecificationFromSchemaVersion - returns specification struct for given schema version URL, or nil when there is no match.

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
	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
	ParentRule *Rule         // Allows accessing parent Rule
	Request    *http.Request // The request that's been generated in order to call the endpoint
	Header     http.Header   // ResponseHeader
	Body       string        // ResponseBody
}

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 NewTestCase

func NewTestCase() *TestCase

NewTestCase creates an Context thats initialised correctly with a map structure which holds the context parameters

func (*TestCase) ApplyContext

func (t *TestCase) ApplyContext() (*http.Request, error)

ApplyContext - at the end of ApplyInputs on the testcase - we have an initial http request object ApplyContext, applys context parameters to the http object. Context parameter typically involve variables that originaled in discovery The functionality of ApplyContext will grow significantly over time.

func (*TestCase) ApplyExpects

func (t *TestCase) ApplyExpects(res *http.Response, rulectx *Context) (bool, error)

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 occured, where it occured 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

func (t *TestCase) ApplyInput(rulectx *Context) (*http.Request, error)

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 and 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) Dump

func (t *TestCase) Dump(print bool)

Dump - TestCase helper

func (*TestCase) GetExcludedPermissions

func (t *TestCase) GetExcludedPermissions() []string

GetExcludedPermissions return a list of excluded permissions

func (*TestCase) GetIncludedPermission

func (t *TestCase) GetIncludedPermission() []string

GetIncludedPermission returns the list of permission names that need to be included in the access token for this testcase. See permission model docs for more information

func (*TestCase) GetPermissions

func (t *TestCase) GetPermissions() (included, excluded []string)

GetPermissions returns a list of Permission objects associated with a testcase

func (*TestCase) Prepare

func (t *TestCase) Prepare(ctx *Context) (*http.Request, error)

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) Validate

func (t *TestCase) Validate(resp *http.Response, rulectx *Context) (bool, error)

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
TODO - cater for returning multiple validation failures and explanations
NOTE: Vadiate will only return false if a check fails - no checks = true

type TestCaseExecutor

type TestCaseExecutor interface {
	//ExecuteTestCase(r *http.Request, t *TestCase, ctx *Context) (*http.Response, error)
	ExecuteTestCase(r *http.Request, t *TestCase, ctx *Context) (*http.Response, error)
}

TestCaseExecutor defines an interface capable of executing a testcase

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL