Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

plan for pre-scripting or post-scripting? #831

Open
huangjj27 opened this issue Sep 17, 2022 · 16 comments
Open

plan for pre-scripting or post-scripting? #831

huangjj27 opened this issue Sep 17, 2022 · 16 comments

Comments

@huangjj27
Copy link

huangjj27 commented Sep 17, 2022

I may need some computation like extracting a field in a JSON, and then parsing it from a base64 string and checking the content in it, or encoding a data structure into base64 before I send it. But I haven't found similar features in the document nor in the issue board. Is it planned or Someone has any walk-around advice?

@fabricereix
Copy link
Collaborator

Hello,
we plan to add some function/helpers to apply to a variable (similar to #606).
Your use case seems interesting, can you please give us an example?

@huangjj27
Copy link
Author

can you please give us an example?

Here is an example for my use case:

POST {{host}}/login
{
    "data": {
        "phone": "{{developer_phone}}",
    }
}
[BeforeSend]
# encrypt data before sending
python = "
req_body = request.body
req_body.encrypted = my_encrypt(req_body.data) # my_encrypt function defined in the outside cipher.py file
del req_body.data
request.body = req_body
"

HTTP/1.1 200
[BeforeAsserts]
# data decrypted before asserting
python = "
res_body = my_decrypt(respone.body) # my_decrypt function defined in the outside cipher.py file
respone.user_name = res_body.user
"

[Asserts]
variable "user_name" == "Bob"

[AfterAsserts]
py = "
# do something like collect into a html report file
"

while the details can be adjusted, What I really want, is a machanics like postman's pre-requests and tests that can manuplate the body or headers etc:

  1. reuse code sinppet or file
  2. do anything before or after asserts that can be programming

Alternatives

a plugin that can manuplate body/headers/cookies and make assertations in hurls. For example, a JWT decoded by the plugin and extract the user field for assert.

@huangjj27
Copy link
Author

huangjj27 commented Sep 19, 2022

I don't think I make it clear. In our system, we have a collection of test cases in Postman, where some computation need to be done before sending a request and after receiving a response. However, Postman's export is not so easy to manuplate, while I want to make all the test cases readable and managed in text format, so that I could make it managed in a git repo. Hurl is very suitable for my sense, except the lack of complex computation.

@fabricereix
Copy link
Collaborator

Thanks for your use case. That makes the discussion a lot more concrete.

We agree that plugging a programming language is more powerful, and thus very attractive.
But it does not really fit well with Hurl declarative, simplicity and performance objectives.

It does not mean that we should not support your use case.
We plan to add simple function/helpers in the template and add additional sections ([xxx]) that could make possible.

We could encrypt the request body as follow:

POST {{host}}/login
[Variables]
iv: {{random(16)}}
key: ABCDEF
body: {"data": {"phone": "{{developer_phone}}" }}

{{body | encrypt_aes iv key)}}

To process/decrypt the response, we could add a query/subquery.
For example

[Captures]
decrypted_body: {{ body | decrypt_aes key}}
[Asserts]
variable "decrypted_body" jsonpath "$.user_name" == "Bob"

For the time-being, you can send your request body from an external file

POST {{host}}/login
file,encrypted_data.bin;

But adding an assert on the response is not that easy.
We should therfore probably try to support that first.

@huangjj27
Copy link
Author

{{body | encrypt_aes iv key)}}

I think encrypt_aes make sense, still I may needs more different utils, maybe MD5, BASE64, DES, some "custom" flow. Would you mind giving a supported utils plan?

@fabricereix
Copy link
Collaborator

yes, it makes sense to support all these common encoding MD5, base64, DES.
we can start by one of them and see how good/useful it is.

@huangjj27
Copy link
Author

huangjj27 commented Sep 22, 2022

start by one of them

my priority is,first DES and base64(non-url-safe version),then MD5,RSA. How to start the work?

@jcamiel
Copy link
Collaborator

jcamiel commented Sep 22, 2022

We've not started working on spec for this (see #312). We need more design thinking/input before jumping to implementation!

@andreluiznsilva
Copy link

andreluiznsilva commented Oct 20, 2022

I have similar case. In order to test one API, I need to send a file to an AWS S3 bucket first. Right now I need to run the command first followed by the Hurl commands to test the API. Would be nice to run the script/command inside Hurl like the options bellow:

  1. Option with the script on the Hurl file
GET {{host}}/status
[BeforeSend]
sh= "
aws s3 cp my-file.txt s3://my-bucket
"

HTTP/1.1 200
[Asserts]
jsonpath "$.status" == "proceed"
  1. Option calling a external script
GET {{host}}/status
Authorization: 
[BeforeSend]
sh=./upload.sh

HTTP/1.1 200
[Asserts]
jsonpath "$.status" == "proceed"

Another option would be use the AWS S3 REST API to upload the file. However, the request would need to be authenticated and is not a easy authorization. It would require a script or native support to do it as you can see on the AWS instructions to Signing and authenticating REST requests. Example:

POST {{awsHost}}/s3/my-bucket
[BeforeSend]
python = "
request.header["Authorization"]= aws_authorize(request)
"

GET {{host}}/status
HTTP/1.1 200
[Asserts]
jsonpath "$.status" == "proceed"

I think give the option of executing scripts would give flexibility for many different cases.
Maybe shell, python or go templates would be good options

@jon49
Copy link

jon49 commented Aug 14, 2023

A solution to scripts that need to run beforehand is using environment variables. At least in the interim. I have a use case where I want to use Azure Service Bus to send an event but it requires the current date and uri encoded value, e.g. (run in JS),

var CryptoJS = require("crypto-js");

var encoded = encodeURIComponent(pm.variables.get("ServiceBusHost"));
var now = new Date();
var week = 60*60*24*7;
var ttl = Math.round(now.getTime() / 1000) + week;
var signature = encoded + '\n' + ttl; 
var signatureUTF8 = signature;
var hash = CryptoJS.HmacSHA256(signatureUTF8, pm.variables.get("ServiceBusSharedAccessKey"));
var hashInBase64 = CryptoJS.enc.Base64.stringify(hash);
pm.environment.set("SharedAccessSignature", 'sr=' + encoded + '&sig=' + encodeURIComponent(hashInBase64) + '&se=' + ttl + '&skn=RootManageSharedAccessKey');

I'm not sure how to do that in Hurl directly, but I can do that before in another scripting language and just set the environment variable (HURL_myenvironmentvariable).

Just a thought for others working on this problem.

@crbanman
Copy link

crbanman commented Jan 9, 2024

Something like this would be useful our use-case. We're using Hurl for e2e testing our API and would like to re-seed/reset our test database after some operations. We can run the tests one file at a time re-seeding where necessary, however, it would be nice if we could just add a command to run ay any point in the hurl file and then run all of our test files with hurl --test --glob. That way we can have aggregated test results.

@fabricereix
Copy link
Collaborator

Relating to aggregating results, note that all the reports generated by Hurl (JUnit, HTML, TAP) aggregate results by default.

@crbanman
Copy link

True, that is a good point.

But it would simplify my workflow to be able to just run the tests with --glob and not have to maintain a script for running them. It could be that being able to run a command from a .hurl file is too out of scope, but I think it's at least worth considering.

@andersonjoseph
Copy link

We're using Hurl for e2e testing our API and would like to re-seed/reset our test database after some operations

That's my use case too, currently I'm doing it with a bash script, but it would be cool to have some kind of support in a hurl file

@jon49
Copy link

jon49 commented May 6, 2024

I think this is a non issue. Just use your favorite scripting language that runs your hurl files and do any environment work outside of HURL. It works really nicely and gives a lot of flexibility.

@berkes
Copy link

berkes commented Dec 3, 2024

I have another use cases that would greatly benefit from some way to apply logic to inputs.

I'm testing verifiable credentials APIs. Especially the steps to claim the credentials need some logic. The logic there is rather convoluted. E.g. "normalizing" json - so that signing it results in the same signature even if ordering, spacing etc changes. But also signing a challenge-response as "proof of possession" and so on.

I don't expect, nor would want, hurl to have such logic built in. But I do think hurl can be of great help here, as it's merely the preparing of the payload in following requests, based on responses in previous requests. Yet not just (captured) variable interpolation, but probably shelling out to a commandline tool that can do this preparation for it?

What happens on claiming, in broad lines, is the following:

  • client makes authn and autz requests. The responses contain session keys.
  • client combines such keys, with a private key, and other local variables to create and sign a proof of possession jwt.
  • this is included in a json payload to request a credential at a known endpoint.

With hurl, we can now already combine several hurl files and calls in a shell script. Between these calls, in the script, add logic to prepare the input for the next hurl-call. But with that, we'd hardly use the strength of hurl anymore and could just as well call cURL from that script instead.

For this case, "shelling out" would be ideal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants