{"id":27075874,"url":"https://github.com/mhjort/trombi","last_synced_at":"2025-12-12T01:36:18.098Z","repository":{"id":13259154,"uuid":"15944295","full_name":"mhjort/trombi","owner":"mhjort","description":"Load testing library for testing stateful apps with Clojure","archived":false,"fork":false,"pushed_at":"2024-01-04T08:57:45.000Z","size":528,"stargazers_count":239,"open_issues_count":2,"forks_count":20,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-04-05T01:20:04.220Z","etag":null,"topics":["clojure","highcharts","load-testing"],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"epl-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mhjort.png","metadata":{"files":{"readme":"README-old.md","changelog":"CHANGES.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2014-01-15T18:39:13.000Z","updated_at":"2025-03-04T15:41:06.000Z","dependencies_parsed_at":"2024-06-19T05:29:25.944Z","dependency_job_id":"2a4acb27-2379-4a15-8cb0-73236b8ca6a6","html_url":"https://github.com/mhjort/trombi","commit_stats":null,"previous_names":["mhjort/clj-gatling"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mhjort%2Ftrombi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mhjort%2Ftrombi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mhjort%2Ftrombi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mhjort%2Ftrombi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mhjort","download_url":"https://codeload.github.com/mhjort/trombi/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247416328,"owners_count":20935447,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clojure","highcharts","load-testing"],"created_at":"2025-04-06T00:18:16.661Z","updated_at":"2025-12-12T01:36:12.851Z","avatar_url":"https://github.com/mhjort.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# clj-gatling\n\n[![Build Status](https://travis-ci.org/mhjort/clj-gatling.png?branch=master)](https://travis-ci.org/mhjort/clj-gatling)\n[![Dependencies Status](http://jarkeeper.com/mhjort/clj-gatling/status.png)](http://jarkeeper.com/mhjort/clj-gatling)\n\nCreate and run load tests using Clojure (and get fancy reports).\nFor reporting clj-gatling uses Gatling under the hood.\n\n## Installation\n\nAdd the following to your `project.clj` `:dependencies`:\n\n```clojure\n[clj-gatling \"0.7.10\"]\n```\n\n## Usage\n\n### Simple example\n\nThis will make 100 simultaneous http get requests to localhost.\nSingle request is considered to be ok if it returns http status code 200.\n\n```clojure\n\n(use 'clj-gatling.core)\n\n(run-simulation\n  [{:name \"Localhost test scenario\"\n   :requests [{:name \"Root request\" :http \"http://localhost\"}]}] 100)\n```\n\nSimulation run shows some important statistics in console and also\ngenerates exactly the same kind of a html report that Gatling does.\n(clj-gatling uses Gatling internally to do this)\n\n### Defining test scenarios\n\nclj-gatling runs scenarios concurrently. Scenario consists of one or\nmore steps called requests. Scenario is defined as a Clojure map.\n\n```clojure\n\n{:name \"Order book scenario\"\n :requests [{:name \"Open frontpage\" :fn open-frontpage}\n            {:name \"Select book\"    :fn select-book\n             :name \"Pay order\"      :fn pay-order}]}\n```\n\nScenario above consists of three requests. Requests are defined as\na Clojure maps. In request you can specify actual action either\nby giving keyword :http which will do http get request or by\ngiving :fn keyword which lets you to specify your own function.\nThe latter option is a preferred way in clj-gatling.\n\nYour own functions should look like this:\n\n\n```clojure\n\n(defn open-frontpage [callback context]\n  (let [was-call-succesful? (do-your-call-here)\n    (callback was-call-succesful? context)))\n\n```\n\nIdeally your calls should be asynchronous and non-blocking.\nThat's why in function signature clj-gatling uses callback instead\nof function return value. When calling callback function the first\nparameter is boolean which tells clj-gatling whether call was\nsuccesful.\n\nThe second parameter to callback is context that is passed through\nrequests within same scenario and virtual user. You can utilize it\nin a following way:\n\n```clojure\n\n;In \"Select book\" request\n(callback true (assoc context :book-id 1}))\n\n;And then in next requst\n(defn pay-order [callback context]\n  (pay-order-call-with-book-id (:book-id context))\n    ...)\n\n```\n\n### Multiple scenarios\n\nIf you want to run multiple scenarios in same simulation you\ncan specify how requests are divided between scenarios by giving\nspecifying :weight. If you run example below with concurrency\n10 it will run \"Order Book\" with concurrency 8 and other scenario\nwith concurrency 2. If you do not specify weight it is always 1\nwhich balances concurrency evenly between scenarios.\n\n```clojure\n\n[{:name \"Order book\"\n  :weight 4\n  :requests [{:name \"Open frontpage\" :fn open-frontpage}\n             {:name \"Select book\"    :fn select-book\n              :name \"Pay order\"      :fn pay-order}]}\n {:name \"Add new book\"\n  :weight 1 [{:name \"Add book\"       :fn add-book}]}]\n\n```\n\n### Scenario options\n\n#### Skipping requests after failure\n\nBy default clj-gatling will skip further requests in scenario if\nprevious request fails. You can turn this feature of in scenario\nby specifying option :skip-next-after-failure?\n\n```clojure\n\n{:name \"Scenario\"\n  :skip-next-after-failure? false\n  :requests [{:name \"Failing request\" :fn fail}\n             {:name \"Next request\"    :fn success}]}\n```\n### Results\n\nAfter the load test run clj-gatling prints out summary of the results\nto console output and generates detailed graphical results using\n[gatling-highcharts](https://github.com/gatling/gatling-highcharts) library.\n\nCalling `clj-gatling-core/run-simulation` also returns summary as following Clojure\nmap.\n\n```clojure\n{:ok \u003cnumber-of-successful-requests\u003e :ko \u003cnumber-of-failed-requests\u003e}\n```\n\n### Global Options\n\n#### Request timeout\n\nBy default clj-gatling uses timeout for 5000 ms for all functions.\nYou can override that behaviour by setting option :timeout-in-ms\n\n#### Constant load\n\nYou can run same scenario multiple times to generate constant load\nwithin a longer time period by specifying option :requests.\nDefault number of requests is same as number of users (which means\nrun only once). Note! The given number is minimum number of requests\nclj-gatling will make. Due to design choice number of requests actually\nmade can go bit over that (e.g. 1001 instead of 1000).\n\n\n```clojure\n(run-simulation [test-scenario] 10 {:requests 500})\n\n```\n\nYou can run same scenario multiple times within given time period\nto generate constant load by specifying option :duration.\n\n```clojure\n(require '[clj-time.core :as t])\n\n(run-simulation [test-scenario] 10 {:duration (t/minutes 2)})\n\n```\n\n### Examples\n\nSee example project a here: [clj-gatling-example](https://github.com/mhjort/clj-gatling-example)\n\n## Why\n\nAFAIK there are no other performance testing tool where you can specify\nyour tests in Clojure. In my opinion Clojure syntax is very good for\nthis purpose.\n\n\n## Design Philosophy\n\n### Real life scenarios\n\nclj-gatling has same kind of an approach that Gatling has in this sense.\nIdea is to simulate a situation where multiple users use your application\nconcurrently. Users do actions and based on the results do next actions etc.\nAfter the simulation you comprehensive results (nice graphs etc.)\n\nIf you want to just execute single request with high level of concurrency\nsimpler tools like Apache Benchmark can do that. Of course, clj-gatling\ncan do that also but it might be an bit of an overkill for that job.\n\n### No DSL\n\nI am not a fan of complex DSLs. clj-gatling tries to avoid DSL approach.\nIdea is that you should write just ordinary Clojure code to specify the\nactions and the actual scenario definition is an map.\n\nNote! This also means clj-gatling does not have full API for simulating\nhttp requests. There is :http keyword for executing simple http get.\nBut anything more complex than that (http post, checking special\nresponse codes etc.) you should do yourself. I recommend using http-kit\nfor that.\n\n### Distributed load testing\n\n[Clojider](http://clojider.io) is a tool that uses clj-gatling scenarios \nand AWS Lambda technology for running distributed load tests in the cloud.\n\n## Contribute\n\nUse [GitHub issues](https://github.com/mhjort/clj-gatling/issues) and [Pull Requests](https://github.com/mhjort/clj-gatling/pulls).\n\n## License\n\nCopyright (C) 2014 Markus Hjort\n\nDistributed under the Eclipse Public License, the same as Clojure.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmhjort%2Ftrombi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmhjort%2Ftrombi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmhjort%2Ftrombi/lists"}