Giter VIP home page Giter VIP logo

orange-opensource / hurl Goto Github PK

View Code? Open in Web Editor NEW
11.9K 46.0 470.0 168.55 MB

Hurl, run and test HTTP requests with plain text.

Home Page: https://hurl.dev

License: Apache License 2.0

Rust 80.74% Shell 4.08% HTML 3.01% CSS 0.31% Python 7.01% NSIS 0.23% C 0.01% Dockerfile 0.10% PowerShell 3.17% JavaScript 0.32% Roff 0.79% Vim Script 0.10% Emacs Lisp 0.13%
curl http testing-tools cli integration-testing http-client api-testing testing

hurl's Issues

Add Hurl File JSON export

Add an option (with hurlfmt ?) to export an Hurl file (the last) to json, to provide an agnostic file format.

Assert of response cookies

The current query cookie return the cookie value (and ignores the other attributes such as path, domain, ...)
cookie "theme" equals "light"

It would be interesting to fully support cookies as defined in the http spec.

the query cookie could return a Cookie Object instead of a simple string.
This object would include a mandatory string value, an optional domain, an option value, ...

The predicate equals (and matches?) could then be applied on this query taking a String value.
There are several options for the semantic of this String value.

For example

cookie "sessionToken" equals "abc123; Expires=Wed, 09 Jun 2021 10:18:14 GMT"
the path and domain must not be defined in the response cookie

cookie "LSID" equals "DQAAAK…Eaem_vYg; Path=/accounts; Expires=Wed, 13 Jan 2021 22:23:01 GMT; Secure; HttpOnly"
the order of attributes does not matter

cookie "LSID" matches "DQAAAK…Eaem_vYg; Path=/accounts; Expires=.*; Secure; HttpOnly"
when you need to use a regex you explicitly use the matched predicate

instead it could be easier to omit the attribute to ignore the attribute.
cookie "LSID" equals "DQAAAK…Eaem_vYg; Path=/accounts; Secure; HttpOnly"
you don't check the Expires attribute at all. It does not matter whether it is present on not.
But then, how do you check whether a cookie is a session cookie?


Another option: ´cookie´ could be extended as a query expression like jsonpath/xpath:

Check value:
cookie "toto" equals "tata"

Check expires:
cookie "toto[expires]" equals "Wed, 09 Jun 2021 10:18:14 GMT"
cookie "toto[expires]" exist

Check Path:
cookie "toto[path]" matches "/test.*"

We can borrow XPath syntax for attribute:

cookie "toto[@path]" equals "/domain"

Or we can create another type of query ´cookiepath’ and keep the actual ´cookie´ query.


Possible query syntax:

  • cookie "toto[expires]" exist
  • cookie "toto[@expires]" exist
  • cookie "toto.expires" exist
  • cookie "toto@expires" exist

=> cookie "toto[Expires]" exist is accepted as the syntax

Possible attributes:
Expires=
Max-Age=
Domain=
Path=
Secure
HttpOnly
SameSite=Strict
SameSite=Lax
SameSite=None

cookie "toto[max-age]" exist
cookie "toto[Max-Age]" exist equivalent


Template variable should probably also be supported for the cookie name.
cookie "{{cookie_name}}[Expired]"


Definition of queries in the grammar

xpath-query 	= "xpath" sp sp* quoted-string
cookie-query 	= "cookie" sp sp* quoted-string

contrary to xpath, the cookie-query is both specific to hurl and very easy.
it could be fully described as follow

cookie-query 	= "cookie" sp sp* """  cookie-query-expr  """
cookie-query-expr = cookie-query-name ( "[" sp* cookie-query-attribute sp* "]" )
cookie-query-name = <[a-zA-Z0-9{}]+>
cookie-query-attribute = Value | value
                       | Expires | expires
                       | Max-Age | max-age
                       | Domain | domain
                       | Path | path
                       | Secure | secure
                       | HttpOnly | httponly
                       | SameSite | samesite

The parsing implementation can choose to be a bit stricter than the grammar

for example,
rejecting escape character
cookie "toto\u{5B}Expires]"

accepting variable only for the cookie name
cookie "toto[{{field}}]"

Do not add header Expect automatically

by default, curl might add the Expect: 100-continue header automatically, for example for a PUT request.

In Hurl, the header will never be sent implicitly.
It would have to be added explicitly in the request header.

Serialization of cookie query for Expires attributes with hurlfmt

When exporting an Hurl file containing a cookie query with Expires attributes, the serialized attribute is Expire:

GET http://localhost

HTTP/1.1 200
[Asserts]
cookie "Session[Expires]" exists
$ hurlfmt --format json /tmp/test.hurl
{
  "entries": [
    {
      "request": {
        "method": "GET",
        "url": "http://localhost"
      },
      "response": {
        "version": "HTTP/1.1",
        "status": 200,
        "asserts": [
          {
            "query": {
              "type": "cookie",
              "expr": "Session[Expire]"
            },
            "predicate": {
              "type": "exist"
            }
          }
        ]
      }
    }
  ]
}

add the --concurrency option to launch multiple runs of *.hurl files instead of one

Hi guys 😄

In the context of our project we see two huge advantages using hurl :

  • It is an ideal solution for functionally testing all the page sequences what we call customer paths on our web application. This allows us to guarantee the non-regression between versions.
  • The simplicity of its language allows non-developers to generate a multitude of scenarios easily.

However, we cannot "yet" use hurl for our metrology tests, forcing us to duplicate all our scenarios in other tools that are less accessible to non-developers... 😢

Currently when I launch this command

hurl a.hurl b.hurl c.hurl

hurl runs each *.hurl file one time, first a.hurl, then b.hurl, then c.hurl.

─ BEGIN
       ├─ a.hurl
                ├─ b.hurl
                         ├─ c.hurl
─ END

I propose you to add the --concurrency option allowing hurl to launch multiple runs of each *.hurl file at a time, for example:

hurl --concurrency 3 a.hurl b.hurl c.hurl
─ BEGIN
       ├─ a.hurl ├─ a.hurl ├─ a.hurl
                                    ├─ b.hurl ├─ b.hurl ├─ b.hurl
                                                                 ├─ c.hurl ├─ c.hurl ├─ c.hurl
─ END

What do you think about it ?

Allow cargo install

Currently only cargo build is used in the CI to build hurl executable
Update your Cargo.toml so that you can also run cargo install

$ cargo install
error: found a virtual manifest at `...hurl/Cargo.toml` instead of a package manifest

Valid Jsonpath query is not parsed

the jsonpath query $.[0].name should be valid
though this is probably better written as $[0].name

With the following json response body

[
  { "id": 1, "name": "Bob"},
  { "id": 2, "name": "Bill"}
]

it should return "Bob"

Improving Assert Error for String

Here is a typical assert error in hurl.

error: Assert Failure
  --> tests/error_assert_value_error.hurl:8:0
   |
 8 | jsonpath "$.count" greaterThan 5
   |   actual:   int <2>
   |   expected: greater than int <5>
   |

This error is quite clear, but for string comparison, it might not be as clear.

For example, for multiline string, you may receive the following error

error: Assert Failure
  --> test.hurl:4:0
   |
 4 | body equals "one\ntwo\nthree"
   |   actual:   string <one
   |   to
   |   three>
   |   expected: string <one
   |   two
   |   three>
   |

It could be better to display both the actual and expected strings on one line.
Converting the newline character to \n

The previous error would become:

error: Assert Failure
  --> test.hurl:4:0
   |
 4 | body equals "one\ntwo\nthree"
   |   actual:   string <one\nto\nthree>
   |   expected: string <one\ntwo\nthree>
   |

To go one step further, the different characters could be highlighted (for example in red)
one\ntwo\nthree

Typo in greater than and less than JSON export

When exporting "greater than" and "less than" predicates, the value for type in the JSON export should reflect the grammar naming;

For example:
"less than" predicate is defined as less-predicate in Hurl grammar and should be export as {"type":"less"...}

Update hurlfmt usage

use --output option with value (text, json, html)
instead of dedicated option --json and --html

Add option --compressed

Add curl option --compressed:

  • add header request 'Accept-Encoding'
  • automatically decompress the body of the last response (if this one has been compressed)

Note that the body of all the other responses won't be decompressed.

Add comparison predicates

add the 4 comparison predicates:

  • greaterThan
  • greaterThanOrEquals
  • lessThan
  • lessThanOrEquals

They can all take an Integer or a float param as defined in the grammar

Improving pattern for regex capture and matches predicates

Currently, regex patterns are used in :

  • regex query
  • matches predicate
GET http://localhost:8000/assert-regex

HTTP/1.0 200
[Asserts]
regex "Hello ([0-9]+)!" not exists
regex "Hello ([a-zA-Z]+)!" equals "World"
body matches "Hello [a-zA-Z]+!"

Pattern in Hurl grammar use quoted-string: the problem is that backslash in quoted-string should be escaped. So to use special character in pattern (like \d, \s), backslash should be escaped, degrading the readability of the pattern:

regex "Hello (\\d)!" not exists

In Rust, Python, Kotlin, raw strings are used to improve the regex readability. In Rust, for instance:

use regex::Regex;
let re = Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap();
assert!(re.is_match("2014-01-01"));

In the Hurl grammar, we already have raw string (```something\ntutu``` is literally the string "something\ntutu" without a newline between something and tutu). We could reuse this syntax when using regex query or matches predicates:

Before:

GET http://localhost:8000/assert-regex

HTTP/1.0 200
[Asserts]
regex "abc(\\d+)!" exists
jsonpath "$.date1" matches "\\d{4}-\\d{2}-\\d{2}"

After:

GET http://localhost:8000/assert-regex

HTTP/1.0 200
[Asserts]
regex ```abc(\d+)!``` exists
jsonpath "$.date1" matches ```\d{4}-\d{2}-\d{2}```

We could also introduce another syntax, like Python raw string and Rust raw string and keep ``` for body raw string:

GET http://localhost:8000/assert-regex

HTTP/1.0 200
[Asserts]
regex r"abc(\d+)!" exists
jsonpath "$.date1" matches r"\d{4}-\d{2}-\d{2}"

raw-string like r"abcd" could be used anywhere a quoted-string is used (not limited to regex capture and matches predicate)

Have a nice diff when comparing bodies

It looks like when using body assertions there is no simple way to compare actual and expected values.

E.g. : I make a request that returns body

{
    "id": 0,
    "name": "Frieda",
    "picture": "images/scottish-terrier.jpeg",
    "age": 3,
    "breed": "Scottish Terrier",
    "location": "Lisco, Alabama"
}

In my hurl file is as follows :

# Get a doggy thing:
GET https://example.net/api/dogs/

HTTP/1.1 200
{
    "id": 0,
    "name": "Julien",
    "picture": "images/scottish-terrier.jpeg",
    "age": 3,
    "breed": "Scottish Terrier",
    "location": "Lisco, Alabama"
}
<img width="1033" alt="Capture d’écran 2020-11-20 à 14 55 40" src="https://user-images.githubusercontent.com/113336/99807944-77a2ee80-2b40-11eb-8855-ce559a130fcf.png">

The output is

error: Assert Body Value
  --> ./integration/test-files/nominal/edito/accessory-orange.hurl:36:1
   |
36 | {
   | ^ actual value is < {
    "id": 0,
    "name": "Frieda",
    "picture": "images/scottish-terrier.jpeg",
    "age": 3,
    "breed": "Scottish Terrier",
    "location": "Lisco, Alabama"
} >

Would it be possible to have a simple way to diff the actual and expected ? Like what is possible with JUnit failed string comparisons.

Capture d’écran 2020-11-20 à 14 56 41

Predicates with not qualifier

The not qualifier in the predicate negates most of the time the predicate result.

But there are a few cases, for which it does not invert a predicate failure.
Hurl detects some inconsistencies between the predicate and the value to which it is applied and prefer to make the assert fail.

Example 1 - the value (returned by the query) is 1 (integer)

All the following predicates fail:

equals 2
equals null
contains "toto"

Negating the predicate does not necessarily make the predicate succeeds.

not equals 2       
not equals null  
not contains "toto" => failure

The last one fails because the contains predicate only apply to String value, and thus it does not make sense to apply it to a integer value.
This is equivalent to a type error.

Example 2 - the value is not found

All the following predicates fail:

exist
equals 1
contains "toto"

all these predicates will success if there are negated

not exist
not equals 1
not contains "toto"

There can't be any "type checking" when no value is returned.

Example 3 - the value is present but does not have a value

for example, the Secure cookie attribute, it is present or not
but it does not have a value

All the following predicates fail:

equals true
equals false
equals 1
contains "toto"

All these predicates will fail even if they are negated.

not equals true
not equals false
not equals 1
not contains "toto"

They must be applied to a value.
exist is the only predicate that can be applied.

Can not parse user in url (Basic Authentication)

Hurl should support a user defined within a url for basic authentication

$ echo GET http://bob:secret@localhost:8000/basic-authentication | hurl
error: Parsing literal
  --> -:1:22
   |
 1 | GET http://bob:secret@localhost:8000/basic-authentication
   |                      ^ expecting 'line_terminator'
   |

Improving Assert Error for a given textual body

Response body can be tested directly without explicit asserts as follow:

test.hurl
1  GET http://example.com/text
2  HTTP/1.1 200
3  ```
4  one
5  two
6  three
7  ```

If the server returns the following response

one 
to
three

the following error will be produced:

error: Assert Body Value
  --> test.hurl:4:1
   |
 4 | one
   | ^ actual value is <one
   |   to
   |   three>

Instead of taking into account the full multiline body, we could focus on the first line that differs.

The previous errors would become:

error: Assert Body Value
  --> test.hurl:5:1
   |
 5 | two
   | ^ actual value is <to>
   |   

This fits quite well with the line-oriented structure of hurl files.

Testing json output can also be a good example.

test.hurl
1  GET http://example.com/json
2  HTTP/1.1 200
3  {
4     "name": "Bob",
5     "age": 32
6  }

If the server returns the following response

{
   "name": "Bob",
   "age": 30
}

The following error will be produced:

error: Assert Body Value
  --> test.hurl:3:1
  |
3 | {
  | ^ actual value is <{
  |       "user": "Bob"
  |       "age": "30"
  |   }>

Taking into account only the first line in error, we get the following error instead:

error: Assert Body Value
  --> test.hurl:5:1
   |
 5 |    "age": 32
   |  ^ actual value is <    "age": 30>
   |   

We could even position the error at the exact different chracter

error: Assert Body Value
  --> test.hurl:5:12
   |
 5 |    "age": 32
   |            ^ actual value is <0>
   |   

Request Cookies Section should not change cookie store

Cookies defined the request Cookies section should just add cookies in the request but should not change cookie storage.
This is consistent with curl.

For example: Send cookie1 in the request and cookie2 set from server endpoind

$ curl \
    --cookie cookie1=value1 \
    --cookie-jar /tmp/cookies \
    http://httpbin.org/cookies/set/name2/value2
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>Redirecting...</title>
<h1>Redirecting...</h1>
<p>You should be redirected automatically to target URL: <a href="/cookies">/cookies</a>. ..

$ cat /tmp/cookies 
# Netscape HTTP Cookie File
# https://curl.haxx.se/docs/http-cookies.html
# This file was generated by libcurl! Edit at your own risk.

httpbin.org	FALSE	/	FALSE	0	name2	value2

with the current hurl

$ cat <<END | hurl --cookie-jar /tmp/cookies
GET http://httpbin.org/cookies/set/cookie2/value2
[Cookies]
cookie1: value1
END

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>Redirecting...</title>
<h1>Redirecting...</h1>
<p>You should be redirected automatically to target URL: <a href="/cookies">/cookies</a>...

$ cat /tmp/cookies 
# Netscape HTTP Cookie File
# This file was generated by hurl

httpbin.org	FALSE	/	FALSE	0	cookie1	value1
httpbin.org	FALSE	/	FALSE	0	cookie2	value2

Runner directives / Cookies Section behavior

Currently, setting a cookie via the cookie section updates the cookiejar
in order to send a cookie without updated the cookiejar, an explicit header 'Cookie' must be used

In the future, we should be able to interact with the runner in a hurl file with predefined directives
(such as clear cookie storage)

Type input variables

Values used in Hurl in Captures/Assert are typed (integer, boolean, string,...)
On the opposite, the input variables (from the option --variable) are all strings.

sample.hurl 
 1  GET http://localhost:8000/hello
 2  HTTP/* 200
 3  [Asserts]
 4  variable "count" equals "1"
 5  variable "count" equals 1

$ hurl --variable count=1 sample.hurl 
error: Assert Failure
  --> /tmp/sample.hurl:5:0
   |
 5 | variable "count" equals 1
   |   actual:   string <1>
   |   expected: int <1>
   |

It will be interesting to type the input variable implicitly.
The string <1> should be treated as integer, therefore the first assert should fail rather than the second.

Similarly, the value should be treated as bool.
To force a string value, the value can be quoted.
This is consistent with the predicate value.

For example, the id <123> is passed as string as follow:

hurl --variable id='"123"' sample.hurl 

Add predicates to test value types

Add the predicates isInteger, isFloat, isBoolean, isString, isCollection

for example, for the following json response

{
    "count": 4,
}

The following asserts fails

jsonpath "$.count" isString
jsonpath "$.count" isFloat

while the following assert is successful
jsonpath "$.count" isInteger

MultipartFormData is not present in json export

MultipartFormData is not present in json export.

With this file:

POST http://localhost:8000/multipart-form-data
[MultipartFormData]
key1: value1
upload1: file,hello.txt;
upload2: file,hello.html;
upload3: file,hello.txt; text/html

HTTP/1.0 200

and

hurl --json /tmp/test.json -v integration/tests/multipart_form_data.hurl

The report is :

[
  {
    "filename": "integration/tests/multipart_form_data.hurl",
    "entries": [
      {
        "request": {
          "method": "POST",
          "url": "http://localhost:8000/multipart-form-data",
          "queryString": [],
          "headers": [],
          "cookies": [],
          "body": ""
        },
        "response": {
          "httpVersion": "HTTP/1.0",
          "status": 200,
          "cookies": [],
          "headers": [
            {
              "name": "Content-Type",
              "value": "text/html; charset=utf-8"
            },
            {
              "name": "Content-Length",
              "value": "0"
            },
            {
              "name": "Server",
              "value": "Werkzeug/1.0.1 Python/3.8.5"
            },
            {
              "name": "Date",
              "value": "Mon, 02 Nov 2020 13:00:52 GMT"
            }
          ]
        },
        "captures": [],
        "asserts": [
          {
            "actual": "1.0",
            "expected": "1.0"
          },
          {}
        ],
        "time": 9
      }
    ],
    "success": true,
    "time": 9,
    "cookies": []
  }
]

Hurl usage doesn't end with newline

When typing hurl + enter, Hurl's usage is shown. It should end with a newline.
Actual:

~/Documents/Dev/hurl-jvm $ hurl
hurl 0.99.13
Run hurl FILE(s) or standard input

USAGE:
    hurl [OPTIONS] [--] [INPUT]...

OPTIONS:
        --append                              Append sessions to json output
        --color                               Colorize Output
        --compressed                          Request compressed response (using deflate or gzip)
        --connect-timeout <SECONDS>           Maximum time allowed for connection
    -b, --cookie <FILE>                       Read cookies from FILE
    -c, --cookie-jar <FILE>                   Write cookies to FILE after running the session (only for one session)
...
        --variable <NAME=VALUE>...            Define a variable
    -v, --verbose                             Turn on verbose output
    -h, --help                                Prints help information
    -V, --version                             Prints version information

ARGS:
    <INPUT>...    Sets the input file to use~/Documents/Dev/hurl-jvm $ 

Expected:

~/Documents/Dev/hurl-jvm $ hurl
hurl 0.99.13
Run hurl FILE(s) or standard input

USAGE:
    hurl [OPTIONS] [--] [INPUT]...

OPTIONS:
        --append                              Append sessions to json output
        --color                               Colorize Output
        --compressed                          Request compressed response (using deflate or gzip)
        --connect-timeout <SECONDS>           Maximum time allowed for connection
    -b, --cookie <FILE>                       Read cookies from FILE
    -c, --cookie-jar <FILE>                   Write cookies to FILE after running the session (only for one session)
...
        --variable <NAME=VALUE>...            Define a variable
    -v, --verbose                             Turn on verbose output
    -h, --help                                Prints help information
    -V, --version                             Prints version information

ARGS:
    <INPUT>...    Sets the input file to use
~/Documents/Dev/hurl-jvm $ 

When exporting greater and less predicates in JSON, value is exported as string

When exporting greater and less predicates in JSON, value is exported as string.

integration/tests/assert_json.hurl :

GET http://localhost:8000/assert-json
HTTP/1.0 200
[Asserts]
...
jsonpath "$.count" greaterThan 1

In integration/tests/assert_json.json:

{
  "query": {
    "type": "jsonpath",
    "expr": "$.count"
  },
  "predicate": {
    "type": "greater-than",
    "value": "1"
  }
}

Add option --variables-file / --variables

Currently, variables can be set at the command-line with the option --variable <name=value>

It can become a bit tedious when the number of variables increases.
Hurl could also read variables from an input properties file with an option like --variables-file <FILE>

The values defined in the properties will be exactly the same as the one define din the command-line.

Arithmetic predicates for number (Integer or Float)

Predicates with numbers such as (equals, greaterThan, ...) are "arithmetic".

For example:
for the following json response

{
    "count": 5,
    "total": 50.0
}

All the following asserts are valid

jsonpath "$.count" equals 5
jsonpath "$.count" equals 5.0
jsonpath "$.count" greaterThan 1
jsonpath "$.count" greaterThan 1.0
jsonpath "$.total" equals 50
jsonpath "$.total" equals 50.0
jsonpath "$.total" greaterThan 0.2
jsonpath "$.total" greaterThan 0

The value type can be checked with an additional predicate

jsonpath "$.count" isInteger
jsonpath "$.total" isFloat

Additional:

The intent for the following assert might not be clear:
jsonpath "$.count" equals 5.0
Do we expect a float value?

In this case, Hurl could emit a warning like:
"You expected value should be replaced by an integer value"

Add option --interactive

Stop between each request.
Map commands to keys.

Start by implemented the following commands:

  • Key Q (Quit)
  • key C (Continue)

Explain --json, --append --html interaction

Let's say we have file1.hurl, file2.hurl file3.hurl.

To get a json view of all files:

hurl --json /tmp/files.json file1.hurl file2.hurl file3.hurl

=> /tmp/files.json does represent the 3 files

hurl --json /tmp/files.json --append file1.hurl
hurl --json /tmp/files.json --append file2.hurl
hurl --json /tmp/files.json --append file3.hurl

=> /tmp/files.json does represent the 3 files

To get a html view of all files:

hurl --html /tmp/ file1.hurl file2.hurl file3.hurl

=> /tmp/*.html does represent the 3 files

hurl --json /tmp/files.json --append --html /tmp/ file1.hurl
hurl --json /tmp/files.json --append --html /tmp/ file2.hurl
hurl --json /tmp/files.json --append --html /tmp/ file3.hurl

=> /tmp/*.html does represent the 3 files

Uncompress response body for textual queries

Textual queries such as xpath and jsonpath assume that the response body is text.
If the response body has been compressed (protocol given in response header Content-Encoding), it must be decompressed automatically.

Default ContentType on Multipart Form Data

Hurl seems to add a default content type for file form datas:

POST http://localhost:8000/multipart-form-data
[MultipartFormData]
key1: value1
upload1: file,hello.txt;
upload2: file,hello.html; text/html
upload3: file,hello.txt; text/plain

HTTP/1.0 200

upload1 file is sent with content type "text/plain" whereas no content type has been specified.

There are two options:

Each part MAY have an (optional) "Content-Type" header field, which
defaults to "text/plain". If the contents of a file are to be sent,
the file data SHOULD be labeled with an appropriate media type, if
known, or "application/octet-stream".

So in this case, upload1 content type should be "application/octet-stream"

  • option 2: when no content type is specified, add a content type base on the file extension.

Curl seems to use option 2:

const char *Curl_mime_contenttype(const char *filename)
{
  /*
   * If no content type was specified, we scan through a few well-known
   * extensions and pick the first we match!
   */
  struct ContentType {
    const char *extension;
    const char *type;
  };
  static const struct ContentType ctts[] = {
    {".gif",  "image/gif"},
    {".jpg",  "image/jpeg"},
    {".jpeg", "image/jpeg"},
    {".png",  "image/png"},
    {".svg",  "image/svg+xml"},
    {".txt",  "text/plain"},
    {".htm",  "text/html"},
    {".html", "text/html"},
    {".pdf",  "application/pdf"},
    {".xml",  "application/xml"}
  };

But I prefer option1 => no implicit.
In any case, we should update the doc to explain the behaviour.

Feature Requests: Imports

First of all: thanks for building this! I really like the general idea.

A great feature would be imports to reuse requests (e.g. login flows) and to be able to scale larger test suites.

Add option -u, --user <user:password>

Add the -user option from curl
in order to specify the user name and password to use for server authentication.

This is useful when querying an API for which you need to provide an Authorization header for each request.

Add checksum body query (md5, sha1, sha256)

It's common to provide a checksum for HTTP resources to be verified.
It could be useful to add a checksum body query in asserts section.

A possible syntax:

GET https://sample.net/toto.tar.bz2

HTTP/1.1 200
[Asserts]
checksum "md5" "4b6fb79adc54152a9e5dc6aa3222b306"
GET https://github.com/Orange-OpenSource/hurl/releases/download/0.99.14/hurl-0.99.14-x86_64-osx.tar.gz

HTTP/1.1 200
[Asserts]
checksum "sha256" equals "b63e2a825d21a3f71f6eeaa439a0b6c8b5126d85c42efc14155b7ff943107f66"

Maybe hash (vs checksum) could be a better query name :

GET https://github.com/Orange-OpenSource/hurl/releases/download/0.99.14/hurl-0.99.14-x86_64-osx.tar.gz

HTTP/1.1 200
[Asserts]
hash "sha256" equals "b63e2a825d21a3f71f6eeaa439a0b6c8b5126d85c42efc14155b7ff943107f66"

A third possible syntax: just use the hash algo type

GET https://github.com/Orange-OpenSource/hurl/releases/download/0.99.14/hurl-0.99.14-x86_64-osx.tar.gz

HTTP/1.1 200
[Asserts]
sha256 equals "b63e2a825d21a3f71f6eeaa439a0b6c8b5126d85c42efc14155b7ff943107f66"

So the possible syntax for the query:

  1. checksum where can be "sha1", "sha256", "md5"
  2. hash where can be "sha1", "sha256", "md5"
  3. 3 new queries sha1, sha256, md5

The two first has the advantage to be flexible for future algo, the last being more static and more succinct.

Note: the return type of the hash should be a string (lowercase, only 0-9, a-f), as there is no binary type in Hurl (for the moment).
So, while this asserts is syntactically correct, it could never be true: sha256 equals "zzz"

The documentation is not really clear about header assertions

Hi,

I have a test with :

GET http://someUrl
Accept-Encoding: gzip

HTTP/1.1 200
Content-Encoding: gzip

My server actually returns :

Content-Encoding: gzip
Content-Encoding: gzip

Which is a bug, but that's another story...

The assertion passes, and maybe it's OK.

But when I change the assertion to :

GET http://someUrl
Accept-Encoding: gzip

HTTP/1.1 200
Content-Encoding: "gzip"

It fails with

    |
 21 | Content-Encoding: "gzip"
    |                   ^^^^^^ actual value is <["gzip", "gzip"]>

Do you think that it is logical ? There is no mention of Header: "expectedValue", only Header: expectedValue. I mean is the Header: expectedValue syntax just a contains() ?

Maybe just a clarification could be added...

Thanks

Support wildcard value in implicit status code reponse

Wildcard * can be used in HTTP version to disable any check on the HTTP version:

GET http://localhost:8000/timeout
HTTP/* 200

It could be useful to also support wildcard for status code.
For instance:

GET http://localhost:8000/timeout
HTTP/* *
[Asserts]
status not equals 200

Status code is explicitly tested not to be equals to 200

add the --parallel option to run *.hurl files in parallel instead of sequentially

Hi guys 😄

Currently when I launch this command

hurl a.hurl b.hurl c.hurl

hurl runs each *.hurl file sequentially, first a.hurl, then b.hurl, then c.hurl.

# tests started sequentially
hurl a.hurl b.hurl c.hurl

─ BEGIN
       ├─ a.hurl
                ├─ b.hurl
                         ├─ c.hurl
─ END

I propose you to add the --parallel option allowing hurl to run *.hurl files in parallel:

# all tests started at same time
hurl --parallel a.hurl b.hurl c.hurl

─ BEGIN
      ├─ a.hurl ├─ b.hurl ├─ c.hurl
─ END
# tests started two at a time
hurl --parallel 2 a.hurl b.hurl c.hurl

─ BEGIN
       ├─ a.hurl  ├─ b.hurl
       ├─ c.hurl
─ END

What do you think about it?

Do you plan to support time-based assertions ?

For some use-cases we would like to check that the http response has been returned within x milliseconds, do you think it has a chance to be implemented ? Maybe we could think about the response payload size also (if Content-Length header is not set correctly)

What are your thoughts ?

Hurl MVP1

MVP1 - End October

  • Packaging .deb files for release (at least Ubuntu, Debian) (add dependencies on libcurl4)
  • Add json export in binary
  • Update doc with json export
  • Update doc with curl
  • Fix cookies section managment
  • Dog fooding libcurl integration
  • Add timeout options
  • Update timeout option doc
  • Update CookiePath doc
  • Testing gzip response

MVP2

  • Interractive session
  • Add Cookie Storage directives
  • libcurl3

Improve Template Support in JSON body

Currently, templates in json body is supported only for string

{
  "name": "{{name}}",
  "age": 30
}

the following file is not supported

{
  "name": "{{name}}",
  "age": {{age}}
}

Note that It is still possible to send this json body with a raw string.
But the content is not validated as json.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.