{"id":15697297,"url":"https://github.com/raphael/resat","last_synced_at":"2025-05-08T22:28:31.201Z","repository":{"id":494402,"uuid":"120986","full_name":"raphael/resat","owner":"raphael","description":"Web scripting engine for the masses","archived":false,"fork":false,"pushed_at":"2010-07-19T23:10:16.000Z","size":169,"stargazers_count":6,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-11-02T11:34:07.361Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","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/raphael.png","metadata":{"files":{"readme":"README.rdoc","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2009-02-03T20:45:22.000Z","updated_at":"2019-08-13T13:58:16.000Z","dependencies_parsed_at":"2022-07-17T00:16:11.959Z","dependency_job_id":null,"html_url":"https://github.com/raphael/resat","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/raphael%2Fresat","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/raphael%2Fresat/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/raphael%2Fresat/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/raphael%2Fresat/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/raphael","download_url":"https://codeload.github.com/raphael/resat/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223823345,"owners_count":17208946,"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-10-03T19:15:47.922Z","updated_at":"2024-11-09T12:05:41.764Z","avatar_url":"https://github.com/raphael.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"= Resat\n\n= DESCRIPTION\n\n== Synopsis\n\nResat is a script engine which allows grouping web requests into \u003cb\u003escenarios\u003c/b\u003e.\n\nA scenario consists of serie of HTTP requests called \u003cb\u003esteps\u003c/b\u003e.\n\nEach step may be associated with \u003cb\u003eguards\u003c/b\u003e and/or \u003cb\u003efilters\u003c/b\u003e and/or \u003cb\u003ehandlers\u003c/b\u003e.\n\nThe syntax used to defined scenarios is simple and can be used by programmers and\nnon-programmers alike. See the WRITING SCENARIOS section below for examples.\n\n* Guards keep making the same request until the response header and/or body\n  satisfy(ies) certain conditions.\n\n* Filters validate the response and may save some of its elements in variables.\n  Variables can be used to define requests, guards and filters.\n\n* Handlers allow writing custom code to handle a request and its response.\n\nScenarios are defined as YAML documents that must adhere to the Kwalify\nschemas defined in \u003ctt\u003eschemas/scenarios.yaml\u003c/tt\u003e. See the comments in this\nfile for additional information.\n\nResat is configured through a YAML configuration file which defines\ndefault values that applies to all requests including the host name,\nbase url, whether to use SSL, common headers and body parameters and\noptionally a username and password to be used with basic authentication.\nThis configuration file is located in \u003ctt\u003econfig/resat.yaml\u003c/tt\u003e by default.\n\n== Why resat?\n\nThere are two main use cases for resat:\n\n1. Scripting: Resat can be used to chaing together a serie of REST API calls\n   that can be used to perform repetitive tasks.\n\n2. API testing: For REST API implementors, resat is the ideal automated\n   regression tool. This is the tool we use at RightScale to test our APIs.\n\n== How to use\n\nresat can be used as a ruby library or as an application. Using it as library\ninvolves instantiating the engine and calling the 'run' method:\n\n require 'resat'\n\n options             = OpenStruct.new\n options.verbose     = false\n options.quiet       = false\n options.norecursion = false\n options.loglevel    = 'info'\n options.logfile     = 'resat.log'\n options.configfile  = 'config/resat.yaml'\n options.schemasdir  = 'schemas'\n\n Resat::Log.init(options)\n engine = Resat::Engine.new(options)\n engine.run('my_scenario.yaml')\n\n if engine.succeeded?\n   puts engine.summary.dark_blue\n else\n   puts engine.summary.dark_red\n end\n puts \"#{engine.requests_count} request(s).\"\n puts \"#{engine.ignored_count} scenario(s) ignored.\"\n puts \"#{engine.skipped_count} YAML file(s) skipped.\"\n\nSee the examples and usage sections below for using resat as an application.\n\n== Examples\n\nRun the scenario defined in scenario.yaml:\n\n $ resat scenario.yaml\n\nExecute scenarios defined in the 'scenarios' directory and its\nsub-directories:\n\n $ resat scenarios\n\nOnly execute the scenarios defined in the current directory, do not execute\nscenarios found in sub-directories:\n\n $ resat -n .\n\n== Usage\n\n resat [options] target\n\n For help use: resat -h\n\n== Options\n\n -h, --help Display help message\n -v, --version Display version, then exit\n -q, --quiet Output as little as possible, override verbose\n -V, --verbose Verbose output\n -n, --norecursion Don't run scenarios defined in sub-directories\n -d, --define NAME:VAL Define global variable (can appear multiple times,\n                       escape ':' with '::')\n -f, --failonerror Stop resat from continuing to run if an error occurs\n -c, --config PATH Config file path (config/resat.yaml by default)\n -s, --schemasdir DIR Path to schemas directory (schemas/ by default)\n -l, --loglevel LVL Log level: debug, info, warn, error (info by default)\n -F, --logfile PATH Log file path (resat.log by default)\n\n= INSTALLATION\n\n* \u003cb\u003eFrom source\u003c/b\u003e: run the following command from the root folder to be able to run resat from anywhere:\n\n $ sudo ln -s `pwd`/bin/resat /usr/local/bin/resat\n\n* \u003cb\u003eUsing the gem\u003c/b\u003e: \n\n $ sudo gem install resat\n\n= DEVELOPMENT\n\n== Source\n\nThe source code of Resat is available via Git: http://github.com/raphael/resat.git\nFork the project and send pull requests to contribute!\n\n== Dependencies\n\nresat relies on Kwalify for validating YAML files:\n\n $ sudo gem install kwalify\n\n* http://www.kuwata-lab.com/kwalify/\n\n= WRITING SCENARIOS\n\nAt the heart of your resat scripts are the scenarios. A scenario consists of\none or more steps. A scenario may include other scenarios. A single execution\nof Resat can apply to multiple scenarios (all scenarios in a given folder).\n\nA simple scenario containing a single step is defined below:\n\n name: List all servers\n steps:\n   - request:\n       operation: index\n       resource:  servers\n\nThe first element of the scenario is its name. The name is used by the command\nline tool for update and error outputs.\n\nThe second element is the list of steps. A step must contain a request. A\nrequest can correspond to one of the REST CRUD operations and apply to a\nresource. CRUD operations are \u003ci\u003ecreate\u003c/i\u003e, \u003ci\u003eshow\u003c/i\u003e, \u003ci\u003eindex\u003c/i\u003e, \u003ci\u003eupdate\u003c/i\u003e,\nand \u003ci\u003edestroy\u003c/i\u003e.\n\nOperations that apply to a single resource rather than to all resources require\nthe \u003ci\u003eid\u003c/i\u003e element:\n\n name: Show server 42\n steps:\n   - request:\n       operation: show\n       resource:  servers\n       id:        42\n\nResat also allows defining \u003ci\u003ecustom\u003c/i\u003e REST operations for making web requests that\ndon't map to a standard CRUD operation. A custom operation is defined by a \u003ci\u003etype\u003c/i\u003e\ncorresponding to the HTTP verb that the request should use (i.e. \u003ctt\u003eget\u003c/tt\u003e, \u003ctt\u003epost\u003c/tt\u003e,\n\u003ctt\u003eput\u003c/tt\u003e or \u003ctt\u003edelete\u003c/tt\u003e) and its name.\n\n name: Twitter Timelines\n steps:\n   - request:\n       resource:  statuses\n       custom:                         # Use a custom operation\n         name:    public_timeline.xml  # Operation name\n         type:    get                  # GET request\n\nAlternatively, the path of a request can be defined manually:\n\n name: Twitter Timeline\n steps:\n   - request:\n       path: statuses/public_timeline.xml\n       type: get\n\nRequests can then be followed by filters which can validate the response and/or\nextract elements from it.\n\n name: Get Mephisto ServerTemplate\n steps:\n   - request:\n       operation:      index\n       resource:       server_templates\n     filters:\n       - name:         get server template href\n         target:       body\n         validators:\n           - field:    server-templates/ec2-server-template[nickname='Mephisto all-in-one v8']/href\n             is_empty: false\n         extractors:\n           - field:    server-templates/ec2-server-template[nickname='Mephisto all-in-one v8']/href\n             variable: server_template_href\n\nVariables that are extracted from a request response can then be used for\nother requests, filters or guards. A variable is used using the \u003ctt\u003e$\u003c/tt\u003e sign\nfollowed by the variable name. A variable may be written to an output file if\nit has the \u003ci\u003esave\u003c/i\u003e element and the configuration file defines an output\nfile. A variable can also be exported to other scenarios that will get run in\nthe same Resat execution (so a scenario can create resources and save their ids\nand a following scenario can reuse the ids to delete or update the resources).\n\nThe element to extract can be a response header or a response body field. If it\nis a response body field then an XPATH query is used to identity which part of\nthe response body should be extracted.\n\nThe value to be extracted can be further defined using a regular expression\nwith a capture block. The regular expression is applied to the field matching\nthe XPATH associated with the extractor.\n\n\u003cb\u003eNote\u003c/b\u003e: Because XPATH is used to define fields in extractors and\nvalidators, only requests that return XML can be followed by filters.\n\n name: Create Mephisto Server\n steps:\n   - request:\n       operation:      create\n       resource:       servers\n       valid_codes:\n         - 201\n       params:\n         - name:       server[nickname]\n           value:      'resat created server'\n         - name:       server[server_template_href]\n           value:      $server_template_href\n         - name:       server[deployment_href]\n           value:      $deployment_href\n     filters:\n       - name:         validate server response\n         target:       body\n         is_empty:     true\n       - name:         extract server id\n         target:       header\n         extractors:\n           - field:    location\n             pattern:  '.*\\/(\\d+)$'\n             variable: server_id\n\nA scenario request can also use \u003ci\u003eguards\u003c/i\u003e. A guard identifies a response\nelement similarly to an extractor (response header or body field identified by\nan XPATH and optionally a regular expression). A guard specifies a value that\nthe element must match together with a period and a timeout that should be used\nto retry the request until the value matches the guard or the timeout is\nreached.\n\n name: Wait until server 42 is operational\n steps:\n   - request:\n       resource:  servers\n       id:        42\n       operation: show\n     guards:\n       - target:  body\n         field:   server/state\n         pattern: 'operational'\n         period:  10\n         timeout: 300\n         name:    server operational\n\nFinally a scenario request can include \u003ci\u003ehandlers\u003c/i\u003e. Handlers can only be\nincluded when resat is used as a library. The handler definition lists a unique\nname followed the corresponding ruby module name.\n\n name: Store servers definitions\n steps:\n   - request:\n       resource:  servers\n       operation: index\n     handlers:\n       - name:    save results\n         module:  ServersPersister\n\nThe ruby module must define a \u003ctt\u003eprocess\u003c/tt\u003e method which accepts two arguments:\n\n  def process(request, response)\n\n* \u003ci\u003erequest\u003c/i\u003e: an instance of Net::HTTPRequest corresponding to the request associated with this handler.\n* \u003ci\u003eresponse\u003c/i\u003e: an instance of Net::HTTPResponse which contains the associated response.\n\nIt should also define a \u003ctt\u003efailures\u003c/tt\u003e method which can return a list of errors. \nThe errors will get logged and optionally stop the execution of resat if the \n\u003ctt\u003efailonerror\u003c/tt\u003e option is set to \u003ctt\u003etrue\u003c/tt\u003e.\n\n= ADDITIONAL RESOURCES\n\n* Refer to the examples (http://github.com/raphael/resat/tree/master/examples)\n  for fully functional and documented scenarios.\n* See the file \u003ctt\u003eschemas/scenarios.yaml\u003c/tt\u003e\n  (http://github.com/raphael/resat/blob/master/schemas/scenarios.yaml) for\n  the complete reference on scenarios syntax.\n\n= LICENSE\n\nResat - Web scripting for the masses\n\nAuthor:: Raphael Simon (\u003craphael@rightscale.com\u003e)\nCopyright:: Copyright (c) 2009 RightScale, Inc. \n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fraphael%2Fresat","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fraphael%2Fresat","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fraphael%2Fresat/lists"}