{"id":21565836,"url":"https://github.com/basesecrete/web_tsunami","last_synced_at":"2025-08-20T20:31:54.615Z","repository":{"id":218542931,"uuid":"742428764","full_name":"BaseSecrete/web_tsunami","owner":"BaseSecrete","description":"Tailor-made load testing for web apps","archived":false,"fork":false,"pushed_at":"2024-02-02T08:35:27.000Z","size":22,"stargazers_count":74,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-12-16T16:55:20.174Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/BaseSecrete.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2024-01-12T13:08:05.000Z","updated_at":"2024-09-17T20:27:26.000Z","dependencies_parsed_at":"2024-01-25T10:56:08.603Z","dependency_job_id":"32561f93-5a9a-4532-ae0e-d1b69ec9b228","html_url":"https://github.com/BaseSecrete/web_tsunami","commit_stats":null,"previous_names":["basesecrete/web_tsunami"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BaseSecrete%2Fweb_tsunami","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BaseSecrete%2Fweb_tsunami/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BaseSecrete%2Fweb_tsunami/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BaseSecrete%2Fweb_tsunami/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/BaseSecrete","download_url":"https://codeload.github.com/BaseSecrete/web_tsunami/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230454424,"owners_count":18228392,"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":[],"created_at":"2024-11-24T10:21:59.352Z","updated_at":"2024-12-19T15:07:51.109Z","avatar_url":"https://github.com/BaseSecrete.png","language":"Ruby","readme":"\u003cimg align=\"right\" width=\"120px\" src=\"./web_tsunami.png\"\u003e\n\n# Web Tsunami\n\nWrite tailor-made scenarios for load testing web apps\n\n## Why\n\nMany good tools already exist for a very long time such as ApacheBench and Siege.\nThe goal is not to replace them.\nBut sometimes, load testing a web app requires to write a custom scenario.\nMy initial requirement was to send requests with unique parameters.\nTo the best of my knowledge, no tool could do this.\n\nThe goal is to focus only on the scenario without thinking about forking, threads and non blocking IOs.\nFortunately there is [Typhoeus](https://github.com/typhoeus/typhoeus) to send parallel HTTP requests.\n\nI wrote a blog post where I share [my load testing habits](https://www.rorvswild.com/blog/2024/ruby-on-rails-load-testing-habits).\nIf you are here, that might interest you.\n\n## How\n\nWeb Tsunami is a tiny class that forks every seconds and sends as many requests as expected.\nIt provide the methods `get`, `post`, `put`, `patch` and `delete`.\nThey all accept the same arguments : `get(url, options = {}, \u0026block)`.\nThe `options` is given to Typhoeus as is.\nIt can contain headers and the request body.\nSee [Typhoeus usage](https://github.com/typhoeus/typhoeus/#usage) for more details.\n\n## Examples\n\nLet's start with a very trivial scenario and I will show you an advanced one after :\n\n```ruby\nrequire \"web_tsunami\"\n\nclass SearchTsunami \u003c WebTsunami::Scenario\n  def run\n    get(\"http://site.example\") do\n      # Block is executed once the response has been received\n      sleep(5) # Simulates the time required for a human to visit the next page\n      get(\"http://site.example/search?query=stress+test\") do |response|\n        # Do whatever you need with the response object or ignore it\n        sleep(10)\n        get(\"http://site.example/search?query=stress+test\u0026page=#{rand(100)}\") do\n          sleep(5)\n          get(\"http://site.example/stress/test\")\n        end\n      end\n    end\n  end\nend\n\n# Simulates 100 concurrent visitors every second for 10 minutes\n# It's a total of 60K unique visitors for an average of 23'220 rpm.\nSearchTsunami.start(concurrency: 100, duration: 60 * 10)\n```\n\nIn this scenario, a visitor comes on the index page, then search for _stress test_, then go on a random page of the search result, and finally found the stress test page.\nIt introduces a unique parameters which is the page number.\nIt's nice, but it could have almost be done with Siege.\nLet me show you a more realistic scenario.\n\n```ruby\nrequire \"web_tsunami\"\n\nclass SessionTsunami \u003c WebTsunami::Scenario\n  def run\n    # The session object stores cookies and automatically submit CSRF token with forms\n    session = WebTsunami::Session.new(self, \"https://site.example\")\n    session.get(\"/\") do\n      session.get(\"/account/new\") do\n        # An authenticity_token param is automatically added by the session\n        session.post(\"/account\", body: {account: {email: \"#{rand(1000000)}@email.test\", password: \"password\"}}) do |response|\n          # The session stores the Set-Cookie header and will provide it to the next requests\n          session.get(\"/dashboard\") do # Redirection after registration\n            # And so on\n          end\n        end\n      end\n    end\n  end\nend\n\nSessionTsunami.start(concurrency: 100, duration: 60 * 10)\n```\n\nThis is more realistic because it handles CSRF tokens and cookies.\nThus the scenario can submit forms and behaves a little bit more like a real visitor.\n\n## Output and result\n\nWeb Tsunami does not measure response time or print any result.\nIf you are running a load test, that means you should use an APM (application performance monitoring).\nIt already collects and displays all data you need such as throughput, response time and bottlenecks.\n\nSo, the only output are errors.\n\n## License\n\nThe gem is available as open-source under the terms of the [MIT License](https://opensource.org/licenses/MIT).\n\nRails developer? Check out [RoRvsWild](https://rorvswild.com), our Ruby on Rails application monitoring tool.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbasesecrete%2Fweb_tsunami","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbasesecrete%2Fweb_tsunami","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbasesecrete%2Fweb_tsunami/lists"}