gorankusu

package module
v0.6.1 Latest Latest
Warning

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

Go to latest
Published: Apr 5, 2024 License: GPL-3.0 Imports: 28 Imported by: 0

README

Gorankusu

Gorankusu is a Go library that provide HTTP service with web user interface to test HTTP and/or WebSocket endpoints and for load testing HTTP endpoints.

For testing HTTP endpoints it use the lib/http package as the client, a wrapper for standard Go HTTP package. For testing WebSocket endpoints it use the lib/websocket package as the client. For the load testing we use vegeta as the backend.

Go documentation

Usage

See the example package on how to programmatically use and create service using this module, or,

Screenshots

The following screenshot display the main interface to Run or Attack the registered HTTP service,

Main interface

The following screenshot display the result of attack in two forms, vegeta metrics and vegeta histogram,

Attack result

Web user interface (WUI)

By default, the Gorankusu user interface can be viewed by opening in browser at http://127.0.0.1:8217. One can change address through Environment's ListenAddress.

File name format

Each attack result is saved in Environment's ResultsDir with the following file name format,

<Target.ID> "." <HttpTarget.ID> "." <DateTime> "." <Rate> "x" <Duration> "." <ResultsSuffix>

The "DateTime" is in the following layout,

YearMonthDate "_" HourMinuteSeconds

The "ResultsSuffix" is the one that defined in Environment.

Development

Repository:: Link to the source code.

Mailing list:: Link to discussion and where to send patches.

Issues:: Link to report for bug or feature.

Credits

The Gorankusu icon and image is provided by https://www.spriters-resource.com/.

License

Copyright (C) 2021 M. Shulhan ms@kilabit.info

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/.

Documentation

Overview

Package gorankusu is a library and HTTP service that provide web user interface to test HTTP service, similar to Postman, and for load testing.

For the load testing we use vegeta [1] as the backend.

Usage

See the example package on how to programmatically use and create service using this module, or

Screen shots

The following screenshot display the main interface to Run or Attack the registered HTTP service,

https://git.sr.ht/~shulhan/gorankusu/blob/main/_screenshots/gorankusu_example.png

The following screenshot display the result of attack in two forms, vegeta metrics and vegeta histogram,

https://git.sr.ht/~shulhan/gorankusu/blob/main/_screenshots/gorankusu_attack_result.png

Web user interface

By default, the Gorankusu user interface can be viewed by opening in browser at http://127.0.0.1:8217. One can change address through Environment's ListenAddress.

File name format

Each attack result is saved in Environment's ResultsDir with the following file name format,

<Target.ID> "." <HttpTarget.ID> "." <DateTime> "." <Rate> "x" <Duration> "." <ResultsSuffix>

The "DateTime" is in the following layout,

YearMonthDate "_" HourMinuteSeconds

The "ResultsSuffix" is the one that defined in Environment.

License

Copyright 2021, Shulhan <ms@kilabit.info>. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.

References

[1] https://github.com/tsenart/vegeta

Index

Constants

View Source
const (
	// FormInputKindBoolean only used for convertion, for example
	// ToJSONObject.
	// In the WUI, it will be rendered as string.
	FormInputKindBoolean = `boolean`

	// FormInputKindFile define the input for uploading file.
	// This form will rendered as "<input type='file' ...>" on the web
	// user interface.
	// Once submitted, the file name, type, size, and lastModification
	// will be stored under [FormInput] Filename, Filetype, Filesize,
	// and Filemodms.
	FormInputKindFile = `file`

	FormInputKindNumber = `number`
	FormInputKindString = `string`
)

List of valid value for field FormInput Kind.

View Source
const (
	FormDataFilecontent = `filecontent`
	FormDataFilemodms   = `filemodms`
	FormDataFilename    = `filename`
	FormDataFilesize    = `filesize`
	FormDataFiletype    = `filetype`
)

List of additional parameters to be generated and send if the FormInput Kind is FormInputKindFile.

Caller can changes the name by using FormInput FormDataName.

View Source
const DefaultAttackDuration = 10 * time.Second

DefaultAttackDuration define default attack duration per Target. This is default value for [AttackOptions.Duration].

View Source
const DefaultAttackRatePerSecond = 500

DefaultAttackRatePerSecond define default attack rate per second per Target. This is default value for [AttackOptions.RatePerSecond].

View Source
const DefaultAttackTimeout = 30 * time.Second

DefaultAttackTimeout define default timeout for each attack request. This is default value for [AttackOptions.Timeout].

View Source
const DefaultListenAddress = `127.0.0.1:8217`

DefaultListenAddress define default gorankusu server address.

View Source
const DefaultMaxAttackDuration = 30 * time.Second

DefaultMaxAttackDuration define maximum duration attack can run on all Target. This is default value for [Environment.MaxAttackDuration].

View Source
const DefaultMaxAttackRate = 3000

DefaultMaxAttackRate define maximum rate an attack can run. This is default value for [Environment.MaxAttackRate].

View Source
const Version = `0.6.1`

Version of gorankusu module.

Variables

This section is empty.

Functions

This section is empty.

Types

type AttackOptions

type AttackOptions struct {
	// Duration define the duration for each attack to be executed,
	// in seconds.
	// For example, if the AttackRate is 500 and AttackDuration is 10
	// seconds, the total of request for each target will be 5000
	// requests.
	// This field is optional, default to DefaultAttackDuration if its
	// zero.
	Duration time.Duration

	// RatePerSecond define the number of request per second.
	// This field is optional, default to DefaultAttackRatePerSecond if
	// its zero.
	RatePerSecond int

	// Timeout define the overall time to run the attack on each target.
	// This field is optional, default to DefaultAttackTimeout if its
	// zero.
	Timeout time.Duration
	// contains filtered or unexported fields
}

AttackOptions define the options for attacking HTTP endpoint.

type AttackResult

type AttackResult struct {
	TargetID     string // ID of Target.
	HTTPTargetID string // ID of HTTP target which own the result.
	Name         string // Name of output file without path.

	TextReport []byte // TextReport the result reported as text.
	HistReport []byte // HistReport the result reported as histogram text.
	// contains filtered or unexported fields
}

AttackResult represent the output from load testing.

type Environment

type Environment struct {
	// AttackRunning will be set to non-nil if there is a load
	// testing currently running.
	AttackRunning *RunRequest

	// ListenAddress is the address and port where Gorankusu HTTP web
	// will run.
	// If its emtpy, it will set to DefaultListenAddress.
	ListenAddress string `ini:"gorankusu::listen_address"`

	// ResultsDir is the path where the output of load testing will be
	// stored.
	// This field is optional, if its empty it will be set to the working
	// directory where the program is running.
	ResultsDir string `ini:"gorankusu:results:dir"`

	// ResultsSuffix define custom string to add to the file name to
	// uniquely identify results on each run.
	ResultsSuffix string `ini:"gorankusu:result:suffix"`

	// MaxAttackRate define the maximum AttackRate can be set by client.
	// The purpose of this option is to prevent client to set attack rate
	// which may bring down the service to be tested.
	// This field is optional, default to DefaultMaxAttackRate if its
	// zero.
	MaxAttackRate int `ini:"gorankusu::max_attack_rate"`

	// MaxAttackDuration define the maximum duration for an attack to be
	// run on each target.
	// The purpose of this option is to prevent client to attack service
	// and bringing it down.
	// This field is optional, default to DefaultMaxAttackDuration if its
	// zero.
	MaxAttackDuration time.Duration `ini:"gorankusu::max_attack_duration"`

	// IsDevelopment if true run gorankusu in testing mode.
	IsDevelopment bool
	// contains filtered or unexported fields
}

Environment contains global configuration for load testing.

type Example added in v0.6.0

type Example struct {
	*Gorankusu
	// contains filtered or unexported fields
}

Example provide an example how to use the Gorankusu library from setting it up to creating targets.

To run the example, execute

$ go run ./internal/cmd/gorankusu

It will run a web user interface at http://127.0.0.1:8217 .

func NewExample added in v0.6.0

func NewExample(listenAddress string, isDev bool) (ex *Example, err error)

NewExample create, initialize, and setup an example of Gorankusu.

func (*Example) Start added in v0.6.0

func (ex *Example) Start() (err error)

Start the Example servers.

func (*Example) Stop added in v0.6.0

func (ex *Example) Stop()

Stop the Example servers.

type FormInput

type FormInput struct {
	// FormDataName define function to map FormInputKindFile name
	// into different name.
	// For example, instead of,
	//
	//	Content-Disposition: form-data; name="filesize"
	//
	// One can change the "filesize" to "size" using this function, so
	// generated request body would be,
	//
	//	Content-Disposition: form-data; name="size"
	FormDataName func(string) string `json:"-"`

	Label string        `json:"label"`
	Hint  string        `json:"hint"`
	Kind  FormInputKind `json:"kind"`
	Value string        `json:"value"`

	// The name of file for FormInputKindFile.
	Filename string `json:"filename"`

	Filetype string `json:"filetype"`

	// The file size for FormInputKindFile.
	Filesize int64 `json:"filesize"`

	// The file modification in millisecond.
	Filemodms int64 `json:"filemodms"`

	Max float64 `json:"max,omitempty"`
	Min float64 `json:"min,omitempty"`
}

FormInput provide the information to create an input component.

The Label field define the input text. The Hint field provide a description about the input. The Kind field describe the type of input (number, string, and so on). The Value field contains default value for input.

The Max and Min fields is optional, it only affect if the Kind is FormInputKindNumber.

If the Kind is FormInputKindFile, the Filename, Filetype, Filesize, and Filemodms will be filled by request based on the file name, type, size, and modification time.

type FormInputKind

type FormInputKind string

FormInputKind define type for form input.

type Gorankusu

type Gorankusu struct {
	Env   *Environment
	Httpd *libhttp.Server
	// contains filtered or unexported fields
}

Gorankusu is the HTTP server with web user interface and APIs for running and load testing the registered HTTP endpoints.

func New

func New(env *Environment) (gorankusu *Gorankusu, err error)

New create and initialize new Gorankusu service.

func (*Gorankusu) AttackHTTP

func (gorankusu *Gorankusu) AttackHTTP(req *RunRequest) (err error)

AttackHTTP start attacking the HTTP target defined in req.

func (*Gorankusu) AttackHTTPCancel

func (gorankusu *Gorankusu) AttackHTTPCancel() (rr *RunRequest, err error)

AttackHTTPCancel cancel any running attack. It will return an error if no attack is running.

func (gorankusu *Gorankusu) RegisterNavLink(nav *NavLink) (err error)

RegisterNavLink register custom navigation link.

func (*Gorankusu) RegisterTarget

func (gorankusu *Gorankusu) RegisterTarget(target *Target) (err error)

RegisterTarget register Target to be attached to Gorankusu.

func (*Gorankusu) RunHTTP

func (gorankusu *Gorankusu) RunHTTP(req *RunRequest) (res *RunResponse, err error)

RunHTTP send the HTTP request to the HTTP target defined in RunRequest with optional Headers and Parameters.

func (*Gorankusu) Start

func (gorankusu *Gorankusu) Start() (err error)

Start the Gorankusu HTTP server that provide user interface for running and load testing registered Targets.

func (*Gorankusu) Stop

func (gorankusu *Gorankusu) Stop()

Stop the Gorankusu HTTP server.

type HTTPAttackHandler

type HTTPAttackHandler func(rr *RunRequest) vegeta.Targeter

HTTPAttackHandler define the function type that will be called when client send request to attack HTTP target.

func DefaultHTTPAttack added in v0.6.0

func DefaultHTTPAttack() HTTPAttackHandler

DefaultHTTPAttack define the default value for [HTTPTarget.Attack] handler that return vegeta.Targeter.

type HTTPParamsConverter added in v0.6.0

type HTTPParamsConverter func(target *HTTPTarget) (any, error)

HTTPParamsConverter is a handler that will be called inside the Run handler to convert the Params values to type that will be send as request.

func DefaultParamsConverter added in v0.6.0

func DefaultParamsConverter() HTTPParamsConverter

DefaultParamsConverter define default function to convert [HTTPTarget.Params] to its equivalent parameters in HTTP, either as query in URL or as stream of bytes in body.

type HTTPPreAttackHandler

type HTTPPreAttackHandler func(rr *RunRequest)

HTTPPreAttackHandler define the function type that will be called before the actual Attack being called.

type HTTPRequestDumper

type HTTPRequestDumper func(req *http.Request) ([]byte, error)

HTTPRequestDumper define an handler to convert http.Request into RunResponse DumpRequest.

func DefaultRequestDumper added in v0.6.0

func DefaultRequestDumper() HTTPRequestDumper

DefaultRequestDumper define default HTTPRequestDumper that convert http.Request with its body to stream of bytes using httputil.DumpRequest.

The returned bytes have CRLF ("\r\n") replaced with single LF ("\n").

type HTTPResponseDumper

type HTTPResponseDumper func(resp *http.Response) ([]byte, error)

HTTPResponseDumper define an handler to convert http.Response into RunResponse DumpResponse.

func DefaultResponseDumper added in v0.6.0

func DefaultResponseDumper() HTTPResponseDumper

DefaultResponseDumper define default HTTPResponseDumper that convert http.Response with its body to stream of bytes using httputil.DumpResponse.

The returned bytes have CRLF ("\r\n") replaced with single LF ("\n").

type HTTPRunHandler

type HTTPRunHandler func(rr *RunRequest) (runres *RunResponse, err error)

HTTPRunHandler define the function type that will be called when client send request to run the HTTP target.

func DefaultHTTPRun added in v0.6.0

func DefaultHTTPRun() HTTPRunHandler

DefaultHTTPRun default [HTTPTarget.Run] handler that generate http.Request, send it to the target, and store and dump them into RunResponse.

type HTTPTarget

type HTTPTarget struct {
	Params KeyFormInput

	// ParamsConverter define the custom function to convert the Params
	// into HTTP request.
	// This field is optional default to [DefaultParamsConverter].
	ParamsConverter HTTPParamsConverter `json:"-"`

	Headers KeyFormInput

	// Run define the handler that will be called when request to run
	// HTTPTarget received from client (web user-interface).
	// This field is optional, default to [DefaultHTTPRun].
	Run HTTPRunHandler `json:"-"`

	PreAttack HTTPPreAttackHandler `json:"-"`

	// Attack define custom handler to generate [vegeta.Attacker].
	// This field is optional default to [DefaultAttack].
	Attack HTTPAttackHandler `json:"-"`

	// RequestDumper define the handler to store [http.Request] after
	// Run into [RunRequest.DumpRequest].
	// Default to [DefaultRequestDumper] if its nil.
	RequestDumper HTTPRequestDumper `json:"-"`

	// ResponseDumper define the handler to store [http.Response] after
	// Run into [RunRequest.DumpResponse].
	// Default to [DefaultResponseDumper] if its nil.
	ResponseDumper HTTPResponseDumper `json:"-"`

	// ID of target, optional.
	// If its empty, it will generated using value from Name.
	ID string

	Name string // Name of target, required.
	Hint string // Description about what this HTTP target is doing.
	Path string

	Method      libhttp.RequestMethod
	RequestType libhttp.RequestType

	// RawBody contains raw request body that is being read and
	// forwarded to target.
	// It will be used only WithRawBody is true.
	RawBody []byte

	Results []*AttackResult // Results contains list of load testing output.

	sync.Mutex `json:"-"` // Use this inside the Attack to lock resource.

	// AllowAttack if its true the "Attack" button will be showed on user
	// interface and client will be allowed to run load testing on this
	// HTTPTarget.
	AllowAttack bool

	// IsCustomizable allow client to modify the Method, Path, and
	// RequestType.
	IsCustomizable bool

	// WithRawBody if true the request is read and forwarded from Body
	// instead of from Params.
	WithRawBody bool
}

HTTPTarget define the HTTP endpoint that can be attached to Gorankusu.

func (*HTTPTarget) String

func (ht *HTTPTarget) String() string

type KeyFormInput

type KeyFormInput map[string]FormInput

KeyFormInput is the simplified type for getting and setting HTTP headers and request parameters (either in query or in the parameter body).

func (KeyFormInput) ToHTTPHeader

func (kfi KeyFormInput) ToHTTPHeader() (headers http.Header)

ToHTTPHeader convert the KeyFormInputs to the standard http.Header.

func (KeyFormInput) ToJSONObject

func (kfi KeyFormInput) ToJSONObject() (data map[string]interface{})

ToJSONObject convert the KeyFormInput into JSON object. FormInput with Kind is FormInputKindBoolean will be converted to true if the Value is either "true", "yes", or "1".

func (KeyFormInput) ToMultipartFormData

func (kfi KeyFormInput) ToMultipartFormData() (data map[string][]byte)

ToMultipartFormData convert the KeyFormInput into map of string and raw bytes.

func (KeyFormInput) ToURLValues

func (kfi KeyFormInput) ToURLValues() (vals url.Values)

ToURLValues convert the KeyFormInput to the standard url.Values.

type NavLink struct {
	ID   string // Unique ID for this navigation, auto generated from Text.
	Text string // Text to display on navigation. Default to Href if its empty.
	Href string // The URL for navigation.

	// If true, the Href will be opened inside an iframe, otherwise it
	// will opened in new tab.
	OpenInIFrame bool
}

NavLink contains the data for custom navigation link.

type RunRequest

type RunRequest struct {
	WebSocketTarget WebSocketTarget
	HTTPTarget      HTTPTarget
	Target          Target
	// contains filtered or unexported fields
}

RunRequest define the request to run HTTP or WebSocket target.

func (*RunRequest) String

func (rr *RunRequest) String() string

type RunResponse

type RunResponse struct {
	ResponseStatus string
	ResponseType   string

	DumpRequest  []byte
	DumpResponse []byte
	ResponseBody []byte

	ResponseStatusCode int
}

RunResponse contains the raw request and response when running HTTP or WebSocket target.

func (*RunResponse) SetHTTPRequest

func (rres *RunResponse) SetHTTPRequest(dumper HTTPRequestDumper, req *http.Request) (err error)

SetHTTPRequest dump the HTTP request including body into the DumpRequest field.

func (*RunResponse) SetHTTPResponse

func (rres *RunResponse) SetHTTPResponse(dumper HTTPResponseDumper, res *http.Response) (err error)

SetHTTPResponse dump the HTTP response including body into the DumpResponse field.

type Target

type Target struct {
	// HTTPClient that can be used for running HTTPTarget.
	HTTPClient *libhttp.Client `json:"-"`

	// Headers define global headers that will send on all HTTPTargets
	// or WebSocketTargets.
	// The same header can also be defined on HTTPTarget that override
	// the value in here.
	Headers KeyFormInput

	Vars KeyFormInput

	ID   string
	Name string

	// BaseURL contains the target address that serve the service to
	// be tested.
	// This field is required.
	BaseURL string

	Hint string

	HTTPTargets      []*HTTPTarget
	WebSocketTargets []*WebSocketTarget

	Opts AttackOptions
}

Target contains group of HTTPTarget that can be tested by Gorankusu.

type WebSocketRunHandler

type WebSocketRunHandler func(rr *RunRequest) (interface{}, error)

WebSocketRunHandler define a function type that will be called to run the WebSocket target.

type WebSocketTarget

type WebSocketTarget struct {
	Headers KeyFormInput

	// Params contains additional parameters to be passed when running
	// the WebSocket handler.
	// It could be custom HTTP headers, query parameters, or arguments in
	// the body. Its up to the user on how to use the Params inside the
	// Run handler.
	// This field is optional.
	Params KeyFormInput

	Run WebSocketRunHandler `json:"-"`

	// ID of target, optional.
	// If its empty, it will generated by normalized the value of Name.
	ID string

	Name string // Name of target, required.
	Hint string // Description about what this WebSocket target is doing.
}

WebSocketTarget define the target to test WebSocket service.

Directories

Path Synopsis
internal
cmd/gorankusu
Program gorankusu provide an example how to use the Gorankusu module.
Program gorankusu provide an example how to use the Gorankusu module.

Jump to

Keyboard shortcuts

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