KO
|
EN
gitlite — search
Search
#javascript
#python
#hacktoberfest
#react
#ai
#typescript
#llm
#go
#golang
#android
#machine-learning
#rust
#deep-learning
#linux
monkey
★ 23
Open GitHub ↗
@FuzzyMonkeyCo's minion
Download README (.md)
Explore Similar Repositories
HTYFloatBall
:
Linux 平台基于 Qt5 的网速浮窗
3proxy-archive
:
3proxy archive for older versions
DLSC
:
document level sentiment classification implemented by tensorflow.
pixelart
:
video to character animation magic
postcss-icon
:
PostCSS plugin that adds `css icons` from icon sets
// repository documentation
Was this content helpful?
★ 0
(0 ratings)
Select Rating:
★
★
★
★
★
Submit Feedback
Recent Feedback
×
Download README
Do you want to download the
README.md
file for
monkey
?
Download (.md)
# [monkey](https://github.com/FuzzyMonkeyCo/monkey) ~ FuzzyMonkeyCo's minion [](https://goreportcard.com/report/github.com/FuzzyMonkeyCo/monkey) [FuzzyMonkey](https://fuzzymonkey.co) is an automated API testing service that behaves as your users would and minimizes sequences of calls that lead to a violation of your software's properties. [monkey](https://github.com/FuzzyMonkeyCo/monkey) is the official open source client that executes the tests FuzzyMonkey generates. [](https://asciinema.org/a/171571?autoplay=1) ``` monkey M.m.p go1.23.2 linux amd64 Usage: monkey [-vvv] env [VAR ...] monkey [-vvv] [-f STAR] fmt [-w] monkey [-vvv] [-f STAR] lint [--show-spec] monkey [-vvv] [-f STAR] exec (repl | start | reset | stop) monkey [-vvv] [-f STAR] schema [--validate-against=REF] monkey [-vvv] [-f STAR] fuzz [--intensity=N] [--seed=SEED] [--label=KV]... [--tags=TAGS | --exclude-tags=TAGS] [--no-shrinking] [--progress=PROGRESS] [--time-budget-overall=DURATION] [--only=REGEX]... [--except=REGEX]... [--calls-with-input=SCHEMA]... [--calls-without-input=SCHEMA]... [--calls-with-output=SCHEMA]... [--calls-without-output=SCHEMA]... monkey [-f STAR] pastseed monkey [-f STAR] logs [--previous=N] monkey [-vvv] update monkey version | --version monkey help | --help | -h Options: -v, -vv, -vvv Debug verbosity level -f STAR, --file=STAR Name of the fuzzymonkey.star file version Show the version string update Ensures monkey is the latest version --intensity=N The higher the more complex the tests [default: 10] --time-budget-overall=DURATION Stop testing after DURATION (e.g. '30s' or '5h') --seed=SEED Use specific parameters for the Random Number Generator --label=KV Labels that can help classification (format: key=value) --tags=TAGS Only run checks whose tags match at least one of these (comma separated) --exclude-tags=TAGS Skip running checks whose tags match at least one of these (comma separated) --progress=PROGRESS dots, bar, ci (defaults: dots) --only=REGEX Only test matching calls --except=REGEX Do not test these calls --calls-with-input=SCHEMA Test calls which can take schema PTR as input --calls-without-output=SCHEMA Test calls which never output schema PTR --validate-against=REF Validate STDIN payload against given schema $ref --previous=N Select logs from Nth previous run [default: 1] Try: export FUZZYMONKEY_API_KEY=fm_42 export FUZZYMONKEY_SSL_NO_VERIFY=1 monkey update monkey -f fm.star exec reset monkey fuzz --only /pets --calls-without-input=NewPet --seed=$(monkey pastseed) echo '"kitty"' | monkey schema --validate-against=#/components/schemas/PetKind ``` ### Getting started **Recommended way:** using [the GitHub Action](https://github.com/FuzzyMonkeyCo/setup-monkey). Quick install: ```shell curl -#fL https://git.io/FuzzyMonkey | BINDIR=/usr/local/bin sh # or the equivalent: curl -#fL https://raw.githubusercontent.com/FuzzyMonkeyCo/monkey/master/.godownloader.sh | BINDIR=/usr/local/bin sh ``` With Docker: ```shell DOCKER_BUILDKIT=1 docker build -o=/usr/local/bin --platform=local https://github.com/FuzzyMonkeyCo/monkey.git # or the faster: DOCKER_BUILDKIT=1 docker build -o=/usr/local/bin --platform=local --build-arg PREBUILT=1 https://github.com/FuzzyMonkeyCo/monkey.git ``` Or simply install the [latest release](https://github.com/FuzzyMonkeyCo/monkey/releases/latest). ### Configuration `monkey` uses [Starlark](https://github.com/bazelbuild/starlark) as its configuration language: a simple Python-like deterministic language. #### Minimal example `fuzzymonkey.star` file ```python OpenAPIv3( name = "dev_spec", file = "openapi/openapi.yaml", host = "http://localhost:3000", ExecReset = "curl -fsSL -X DELETE http://localhost:3000/api/1/items", ) ``` #### Demos * [demo_erlang_cowboy_simpleREST](https://github.com/FuzzyMonkeyCo/demo_erlang_cowboy_simpleREST) #### A more involved [`fuzzymonkey.star`](./fuzzymonkey.star) ```python # Invariants of our APIs expressed in a Python-like language assert that(monkey.env("TESTING_WHAT", "demo")).is_equal_to("demo") SPEC = "pkg/runtime/testdata/jsonplaceholder.typicode.comv1.0.0_openapiv3.0.1_spec.yml" print("Using {}.".format(SPEC)) monkey.openapi3( name = "my_spec", # Note: references to schemas in `file` are resolved relative to file's location. file = SPEC, host = "https://jsonplaceholder.typicode.com", ) # Note: exec commands are executed in shells sharing the same environment variables, # with `set -e` and `set -o pipefail` flags on. # List here the commands to run so that the service providing "my_spec" # can be restored to its initial state. monkey.shell( name = "example_resetter", # Link to above defined spec. provides = ["my_spec"], # The following gets executed once per test # so have these commands complete as fast as possible. # For best results, tests should start with a clean slate # so limit filesystem access, usage of $RANDOM and non-reproducibility. reset = """ echo ${BLA:-42} BLA=$(( ${BLA:-42} + 1 )) echo Resetting System Under Test... """, ) ## Add headers to some of the requests MY_HEADER = "X-Special" def add_special_headers(ctx): """Shows how to modify an HTTP request before it is sent""" req = ctx.request if type(req) != "http_request": print("`ctx.request` isn't an HTTP request! It's a {}", type(req)) return assert that(MY_HEADER.title()).is_equal_to(MY_HEADER) assert that(dict(req.headers)).does_not_contain_key(MY_HEADER) req.headers.add(MY_HEADER, "value!") print("Added an extra header:", MY_HEADER) # Let's also set a bearer token: token = monkey.env("DEV_API_TOKEN", "dev token is unset!") req.headers.set("authorization".title(), "Bearer " + token) # Let's edit (a possibly-empty) body if req.body == None: req.body = {} req.body["key"] = 42 monkey.check( name = "adds_special_headers", before_request = add_special_headers, tags = ["special_headers"], ) monkey.check( name = "checks_special_headers", after_response = lambda ctx: assert that(dict(ctx.request.headers)).contains_key(MY_HEADER), tags = ["special_headers"], ) ## Ensure some general property def ensure_lowish_response_time(ms): def responds_in_a_timely_manner(ctx): assert that(ctx.response).is_of_type("http_response") assert that(ctx.response.elapsed_ms).is_at_most(ms) return responds_in_a_timely_manner monkey.check( name = "responds_in_a_timely_manner", after_response = ensure_lowish_response_time(1000), tags = ["timings"], ) ## Express stateful properties def stateful_model_of_posts(ctx): """Properties on posts. State collects posts returned by API.""" if type(ctx.request) != "http_request": return # NOTE: response has already been decoded & validated for us. url = ctx.request.url if all([ ctx.request.method == "GET", "/posts/" in url and url[-1] in "1234567890", # /posts/{post_id} ctx.response.status_code in range(200, 299), ]): post_id = url.split("/")[-1] post = ctx.response.body # Ensure post ID in response matches ID in URL (an API contract): assert that(str(int(post["id"]))).is_equal_to(post_id) # Verify that retrieved post matches local model if post_id in ctx.state: assert that(post).is_equal_to(ctx.state[post_id]) return if all([ ctx.request.method == "GET", url.endswith("/posts"), ctx.response.status_code == 200, ]): # Store posts in state for post in ctx.response.body: post_id = str(int(post["id"])) ctx.state[post_id] = post print("State contains {} posts".format(len(ctx.state))) monkey.check( name = "some_props", after_response = stateful_model_of_posts, ) ## Encapsulation: ensure each monkey.check owns its own ctx.state. def encapsulation_1_of_2(ctx): """Show that state is not shared with encapsulation_2_of_2""" assert that(ctx.state).is_empty() monkey.check( name = "encapsulation_1_of_2", after_response = encapsulation_1_of_2, tags = ["encapsulation"], ) monkey.check( name = "encapsulation_2_of_2", after_response = lambda ctx: None, state = {"data": 42}, tags = ["encapsulation"], ) ## A test that always fails def this_always_fails(ctx): assert that(ctx).is_none() monkey.check( name = "always_fails", after_response = this_always_fails, tags = ["failing"], ) ``` ### Issues? Report bugs [on the project page](https://github.com/FuzzyMonkeyCo/monkey/issues) or [contact us](mailto:ook@fuzzymonkey.co). ## License See [LICENSE](./LICENSE)