Can mountebank be used to mock a GET octet-stream image file using stub and predicate? - mountebank

When using a text file, this works like a regular GET
{
"responses": [
{
"is": {
"headers": {
"content-disposition": "attachment; filename=sample_text_file.txt"
},
"statusCode": 200,
"body": "<%- stringify(filename, 'templates/attachments/sample_text_file.txt') %>"
}
}
],
"predicates": [
{
"and": [
{
"equals": {
"method": "GET",
"path": "/resources/4df3dab6-003b-440d"
}
}
]
}
]
}
However, when an image file is used in place of text file, the Mountebank fails to start.

Related

Mountebank predicates doesn't check headers

I have below code and looks like it is not checking headers as a predicate.
{
"responses": [
{
"inject": "<%- stringify(filename, 'Scripts/MyDept/CutOffTime.ejs') %>"
}
],
"predicates": [
{
"matches": {
"method": "GET",
"path": "/cutoff-times",
"query": {
"country": "\\w+"
},
"headers": {
"X-CLIENT-ID": "^[ A-Za-z0-9]*$"
}
}
}
]
}
Strangely, when I pass # as the value to header X-CLIENT-ID it validate and shows the message as no predicate match. Because it is not part of the regex.
Identified the issue,
Basically if you need have multiple predicates need to merge them as below,(using and / or)
{
"responses": [
{
"inject": "<%- stringify(filename, 'Scripts/MyDept/CutOffTime.ejs') %>"
}
],
"predicates": [
{
"and": [
{
"exists": {
"headers": {
"X-CLIENT-ID": true,
}
}
},
{
"matches": {
"method": "GET",
"path": "/cutoff-times",
"headers": {
"X-CLIENT-ID": "^[ A-Za-z0-9]*$"
},
"query": {
"country": "\\w+"
}
}
}
]
}
]
}
Mountebank site
Further matches predicate doesn't check the existence (e.g. header existence)

Is there way to pass path parameter in Mountbank

I was trying to pass path parameter using Mountebank.
Below is working, but there path is static no any parameters.
"predicates": [
{
"equals": {
"method": "GET",
"path": "/accounts",
"query": {
"permissionId": "xxx"
}
}
}
],
"responses": [
{
..... }
]
In case if I need to do GET /accounts/[account-no] where account-no is a parameter
Below regex worked, Please note use matches in case of regex instead of equal
"predicates": [
{
"matches": {
"method": "GET",
"path": "/accounts/\\d+",
"query": {
"permissionId": "xxx"
}
}
}
],
"responses": [
{
..... }
]

Use Mountebank copy behavior in multiple stubs

Is it possible to share a variable between Mountebank stubs?
Here's a high level example:
Stub A:
{
"predicates": [
{
"matches": {
"body": "amount=420"
}
}
],
"responses": [
{
"is": {
"statusCode": 200
},
"body": {
"transaction_id": "123456",
"amount": 420
},
"_behaviors": {
"copy": [{
"from": {"query": "transaction_id"},
"into": "${TRANSACTION1}",
"using": {
"method": "regex",
"selector": "(?<=transaction_id%5D=).{6}"
}
}]
}
Stub B:
{
"predicates": [
{
"matches": {
"body": "approved=420"
}
}
],
"responses": [
{
"is": {
"statusCode": 200
},
"body": {
"transaction_id": "${TRANSACTION1}",
"amount": 420
}
}
The copy _behavior approaches I have tried for Stub B do not seem to recognize the variable specified in Stub A. From the documentation, it seems as though I cannot use copy between these stubs.
As per the developer, this behavior isn't supported at this time. See: https://github.com/bbyars/mountebank/issues/476

Send some of the properties to slack from azure alerts

How can I send some of the properties from AzureMonitorMetricAlert
The full JSON looks like:
{
"schemaId":"AzureMonitorMetricAlert",
"data": {
"version":"2.0",
"properties":null,
"status":"Active",
"context": {
"timestamp":"2019-04-30T14:19:49.4987935Z",
"id":"/subscriptions/xxxxxxxx/resourceGroups/test/providers/microsoft.insights/metricAlerts/500%20response%20code",
"name":"500 response code",
"description":"",
"conditionType":"DynamicThresholdCriteria",
"severity":"3",
"condition": {
"windowSize":"PT5M",
"allOf": [
{
"alertSensitivity":null,
"failingPeriods":null,
"ignoreDataBefore":null,
"metricName":"requests/failed",
"metricNamespace":"microsoft.insights/components",
"operator":null,
"threshold":null,
"timeAggregation":"Count",
"dimensions": [
{
"name":"ResourceId",
"value":"xxxxxxxxx"
},
{
"name":"request/resultCode",
"value":"500"
}
],
"metricValue":null
}
]
},
"subscriptionId":"xxxxxxxxxxxxxxxx",
"resourceGroupName":"test",
"resourceName":"test",
"resourceType":"microsoft.insights/components",
"resourceId":"/subscriptions/xxxxxxxxxxx/resourceGroups/test/providers/microsoft.insights/components/tests",
"portalLink":"https://portal.azure.com/#resource/subscriptions/xxxxxxxx/resourceGroups/dsdsdsdsds"
}
}
}
How can I send message to the slack including text eg: "The alert for ${context.name} was sent."
I was trying with:
"actions": {
"Post_message": {
"inputs": {
"host": {
"connection": {
"name": "#parameters('$connections')['slack']['connectionId']"
}
},
"method": "post",
"path": "/chat.postMessage",
"queries": {
"channel": "CHT0EMJ3H",
"parse": "full",
"text": "tests::::::=>>>>> #{triggerBody()?['context']['name']}"
}
},
"runAfter": {},
"type": "ApiConnection"
}
}
But it doesn't work. If I use just "text": "tests::::::=>>>>> #{triggerBody()}" the full JSON is sent but it is hard to read it since it is parsed as a string.
You can't read the properties because the output of triggerbody() is a string. so you could parse the string to Json firstly then read the properties.
So you need to use the Parse Json action, the Content is the #triggerBody() and the schema click Use sample payload to generate schema and input the Json. With this action you will be able to read the properties.
I test with HTTP Request trigger and send an mail, reading the conditionType with #{body('Parse_JSON')?['data']?['context']?['conditionType']}.

Gmail api proper way to get email message body(text or html) from Users.message resource

I am using Users.messages.get endpoint to get a gmail response which is in this format as per documentation.
What is the proper way to decode/decrypt the message body from above response?
In my case for example, the "parts" array field in response looks like this:
[
{
"partId": "0.0",
"mimeType": "text/plain",
"filename": "",
"headers": [
{
"name": "Content-Type",
"value": "text/plain; charset=\"UTF-8\"; format=flowed; delsp=yes"
},
{
"name": "Content-Transfer-Encoding",
"value": "base64"
}
],
"body": {
"size": 1628,
"data": "R29vZ2xlIGxvZ28NCg0KSGVsbG8gQXBwcyBTY3JpcHQgdXNlciwNCg0KVGhpcyBub3RpZmljYXRpb24gaXMgdG8gYWxlcnQgeW91IG9mIGFuIHVwZGF0ZSB0byBvbmUgb3IgbW9yZSBvZiB5b3VyIEFwcHMgIA0KU2NyaXB0IHByb2plY3RzIHRoYXQgYXJlIGF0dGFjaGVkIHRvIERvY3MsIFNoZWV0cywgYW5kIEZvcm1zIGRvY3VtZW50cyB3aXRoICANCnNjcmlwdCBzaGFyaW5nIHNldHRpbmdzIHRoYXQgZGlmZmVyIGZyb20gdGhvc2Ugb2YgdGhlIGRvY3VtZW50Lg0KDQpTdGFydGluZyBvbiBvciBhZnRlciBKdWx5IDZ0aCwgMjAxNywgdGhvc2Ugc2NyaXB0IHNoYXJpbmcgc2V0dGluZ3Mgd2lsbCBiZSAgDQp1cGRhdGVkIHRvIG1hdGNoIHRob3NlIG9mIHRoZSBkb2N1bWVudHMgdG8gd2hpY2ggdGhleSdyZSBhdHRhY2hlZC4NCg0KVGhlIHNoYXJpbmcgc2V0dGluZ3MgdXBkYXRlIHNpbXBsaWZpZXMgc2hhcmluZyBzZXR0aW5ncyBmb3IgZG9jdW1lbnRzIHdpdGggIA0KYXR0YWNoZWQgQXBwcyBTY3JpcHQgcHJvamVjdHMgYnkgdHJlYXRpbmcgdGhlbSBsaWtlIGEgc2luZ2xlIGRvY3VtZW50Lg0KDQpBcyBhIHJlc3VsdCBvZiB0aGUgc2hhcmluZyBzZXR0aW5ncyB1cGRhdGUsIGFuZCBhY2NvcmRpbmcgdG8gdGhlIGRvY3VtZW50ICANCmFjY2VzcyBsZXZlbCwgc29tZSB1c2VycyBtYXk6DQoNCg0KR2FpbiBvciBsb3NlIGFjY2VzcyB0byBhZmZlY3RlZCBwcm9qZWN0cw0KQ2hhbmdlIHRoZWlyIGFjY2VzcyBsZXZlbHMgKGZvciBleGFtcGxlLCBvd25lciwgZWRpdG9yLCByZWFkZXIpDQoNClRoaXMgY2hhbmdlIHdpbGwgbm90IGFmZmVjdCBzaGFyaW5nIHNldHRpbmdzIGZvciB0aGUgZG9jdW1lbnRzLiBPbmx5ICANCnNoYXJpbmcgc2V0dGluZ3Mgb2YgYXR0YWNoZWQgQXBwcyBTY3JpcHQgcHJvamVjdHMgd2lsbCBiZSB1cGRhdGVkLg0KDQpBIENTViBmaWxlIGF0dGFjaGVkIHRvIHRoaXMgbWVzc2FnZSBsaXN0cyBhbGwgQXBwcyBTY3JpcHQgcHJvamVjdHMgd2hlcmUgIA0KeW91J3JlIHRoZSBvd25lciBhbmQgd2hvc2Ugc2hhcmluZyBzZXR0aW5ncyB3aWxsIGNoYW5nZSBhcyBhIHJlc3VsdCBvZiB0aGlzICANCm1pZ3JhdGlvbi4gUGxlYXNlIHJldmlldyB0aGVzZSBkb2N1bWVudHMgYW5kIGNvbmZpcm0gdGhhdCB0aGVpciBzaGFyaW5nICANCnNldHRpbmdzIGFyZSBhbHNvIGFwcHJvcHJpYXRlIGZvciB0aGVpciBhdHRhY2hlZCBBcHBzIFNjcmlwdCBwcm9qZWN0cy4NCg0KSWYgY2hhbmdlcyBhcmUgcmVxdWlyZWQsIGZvciBlYWNoIGRvY3VtZW50IHdoZXJlIHNldHRpbmdzIG5lZWQgdG8gYmUgIA0KY2hhbmdlZCwgdXNlIG9uZSBvZiB0aGVzZSBtZXRob2RzOg0KDQoNCkluIERvY3Mgb3IgU2hlZXRzLCBjbGljayBTaGFyZS4NCkluIEZvcm1zLCBjbGljayBBZGQgQ29sbGFib3JhdG9yLg0KSW4gR29vZ2xlIERyaXZlLCBjbGljayBTaGFyZS4NCg0KU2luY2VyZWx5LA0KDQpUaGUgQXBwcyBTY3JpcHQgVGVhbQ0KDQoNCsKpIDIwMTcgR29vZ2xlIEluYy4gMTYwMCBBbXBoaXRoZWF0cmUgUGFya3dheSwgTW91bnRhaW4gVmlldywgQ0EgOTQwNDMNCg0KWW91IGhhdmUgcmVjZWl2ZWQgdGhpcyB1cGRhdGUgYXMgYSBHIFN1aXRlIHNlcnZpY2UgYW5ub3VuY2VtZW50Lg0KDQo="
}
},
{
"partId": "0.1",
"mimeType": "text/html",
"filename": "",
"headers": [
{
"name": "Content-Type",
"value": "text/html; charset=\"UTF-8\""
},
{
"name": "Content-Transfer-Encoding",
"value": "quoted-printable"
}
],
"body": {
"size": 3112,
"data": "PCEtLSBUaGlzIGNvbnRhaW5zIENTUyBpbmZvLCBzdGFydHMgdGhlIGJvZHksIGFuZCBpbnNlcnRzIHRoZSBHb29nbGUgbG9nbyBoZWFkZXIgLS0-DQo8c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6IFJvYm90bywgQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICMwMDAwMDA7Ij4gPC9zcGFuPg0KPGRpdiBzdHlsZT0icGFkZGluZy10b3A6IDIycHg7IHBhZGRpbmctYm90dG9tOiA4cHg7IGJvcmRlci1ib3R0b20tc3R5bGU6IHNvbGlkOyBib3JkZXItYm90dG9tLWNvbG9yOiAjZGNkY2RjOyBib3JkZXItYm90dG9tLXdpZHRoOiAxcHgiIHdpZHRoPSIxMDAlIj48c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6IFJvYm90bywgQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICMwMDAwMDA7Ij48aW1nIGFsdD0iR29vZ2xlIGxvZ28iIGJvcmRlcj0iMCIgc3JjPSJodHRwOi8vd3d3LmdzdGF0aWMuY29tL2ltYWdlcy9icmFuZGluZy9nb29nbGVsb2dvLzF4L2dvb2dsZWxvZ29fY29sb3JfMTIweDQ4ZHAucG5nIiBzdHlsZT0iZGlzcGxheTogYmxvY2s7IiB0aXRsZT0iR29vZ2xlIiB3aWR0aD0iMTIwIj4gPC9zcGFuPjwvZGl2Pg0KPHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiBSb2JvdG8sIEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDE0cHg7IGNvbG9yOiAjMDAwMDAwOyI-IDwhLS0gVGhpcyBpcyB0aGUgYmVnaW5uaW5nIG9mIHRoZSBzdWJqZWN0IC0tPiA8L3NwYW4-DQoNCg0KPCEtLSBQbGVhc2UgSU5TRVJUIHRoZSByZWxldmFudCBDdXN0b21lciBDb21tIGdrbXMgc25pcHBldCAtLT4NCjxwPkhlbGxvIEFwcHMgU2NyaXB0IHVzZXIsPC9wPg0KDQo8cD5UaGlzIG5vdGlmaWNhdGlvbiBpcyB0byBhbGVydCB5b3Ugb2YgYW4gdXBkYXRlIHRvIG9uZSBvciBtb3JlIG9mIHlvdXIgQXBwcyBTY3JpcHQgcHJvamVjdHMgdGhhdCBhcmUgYXR0YWNoZWQgdG8gRG9jcywgU2hlZXRzLCBhbmQgRm9ybXMgZG9jdW1lbnRzIHdpdGggc2NyaXB0IHNoYXJpbmcgc2V0dGluZ3MgdGhhdCBkaWZmZXIgZnJvbSB0aG9zZSBvZiB0aGUgZG9jdW1lbnQuPC9wPg0KDQo8cD48c3Ryb25nPlN0YXJ0aW5nIG9uIG9yIGFmdGVyIEp1bHkgNnRoLCAyMDE3PC9zdHJvbmc-LCB0aG9zZSBzY3JpcHQgc2hhcmluZyBzZXR0aW5ncyB3aWxsIGJlIHVwZGF0ZWQgdG8gbWF0Y2ggdGhvc2Ugb2YgdGhlIGRvY3VtZW50cyB0byB3aGljaCB0aGV5JiMzOTtyZSBhdHRhY2hlZC48L3A-DQoNCjxwPlRoZSBzaGFyaW5nIHNldHRpbmdzIHVwZGF0ZSBzaW1wbGlmaWVzIHNoYXJpbmcgc2V0dGluZ3MgZm9yIGRvY3VtZW50cyB3aXRoIGF0dGFjaGVkIEFwcHMgU2NyaXB0IHByb2plY3RzIGJ5IHRyZWF0aW5nIHRoZW0gbGlrZSBhIHNpbmdsZSBkb2N1bWVudC48L3A-DQoNCjxwPkFzIGEgcmVzdWx0IG9mIHRoZSBzaGFyaW5nIHNldHRpbmdzIHVwZGF0ZSwgYW5kIGFjY29yZGluZyB0byB0aGUgZG9jdW1lbnQgYWNjZXNzIGxldmVsLCBzb21lIHVzZXJzIG1heTo8L3A-DQoNCjx1bD4NCiAgPGxpPkdhaW4gb3IgbG9zZSBhY2Nlc3MgdG8gYWZmZWN0ZWQgcHJvamVjdHM8L2xpPg0KICA8bGk-Q2hhbmdlIHRoZWlyIGFjY2VzcyBsZXZlbHMgKGZvciBleGFtcGxlLCBvd25lciwgZWRpdG9yLCByZWFkZXIpPC9saT4NCjwvdWw-DQoNCjxwPjxzdHJvbmc-VGhpcyBjaGFuZ2Ugd2lsbCBub3QgYWZmZWN0IHNoYXJpbmcgc2V0dGluZ3MgZm9yIHRoZSBkb2N1bWVudHMuIE9ubHkgc2hhcmluZyBzZXR0aW5ncyBvZiBhdHRhY2hlZCBBcHBzIFNjcmlwdCBwcm9qZWN0cyB3aWxsIGJlIHVwZGF0ZWQuPC9zdHJvbmc-PC9wPg0KDQo8cD5BIENTViBmaWxlIGF0dGFjaGVkIHRvIHRoaXMgbWVzc2FnZSBsaXN0cyBhbGwgQXBwcyBTY3JpcHQgcHJvamVjdHMgd2hlcmUgeW91JiMzOTtyZSB0aGUgb3duZXIgYW5kIHdob3NlIHNoYXJpbmcgc2V0dGluZ3Mgd2lsbCBjaGFuZ2UgYXMgYSByZXN1bHQgb2YgdGhpcyBtaWdyYXRpb24uIFBsZWFzZSByZXZpZXcgdGhlc2UgZG9jdW1lbnRzIGFuZCBjb25maXJtIHRoYXQgdGhlaXIgc2hhcmluZyBzZXR0aW5ncyBhcmUgYWxzbyBhcHByb3ByaWF0ZSBmb3IgdGhlaXIgYXR0YWNoZWQgQXBwcyBTY3JpcHQgcHJvamVjdHMuPC9wPg0KDQo8cD5JZiBjaGFuZ2VzIGFyZSByZXF1aXJlZCwgZm9yIGVhY2ggZG9jdW1lbnQgd2hlcmUgc2V0dGluZ3MgbmVlZCB0byBiZSBjaGFuZ2VkLCB1c2Ugb25lIG9mIHRoZXNlIG1ldGhvZHM6PC9wPg0KDQo8dWw-DQogIDxsaT5JbiBEb2NzIG9yIFNoZWV0cywgY2xpY2sgPHN0cm9uZz5TaGFyZTwvc3Ryb25nPi48L2xpPg0KICA8bGk-SW4gRm9ybXMsIGNsaWNrIDxzdHJvbmc-QWRkIENvbGxhYm9yYXRvcjwvc3Ryb25nPi48L2xpPg0KICA8bGk-SW4gR29vZ2xlIERyaXZlLCBjbGljayA8c3Ryb25nPlNoYXJlPC9zdHJvbmc-LjwvbGk-DQo8L3VsPg0KDQo8cD5TaW5jZXJlbHksPC9wPg0KDQo8cD5UaGUgQXBwcyBTY3JpcHQgVGVhbTwvcD4NCjwhLS0gRmluYWxseSwgaW5jbHVkZSB0aGUgc3RhbmRhcmQgZm9vdGVyLiBUaGlzIGFsc28gZW5kcyB0aGUgYm9keSAtLT4NCjwhLS0gI2luY2x1ZGUgJy9na21zaWQvNjMyOTg2MycgLS0-DQoNCjwhLS0gRmluYWxseSwgaW5jbHVkZSB0aGUgVXNlciBzdGFuZGFyZCBmb290ZXIuIFRoaXMgYWxzbyBlbmRzIHRoZSBib2R5IC0tPg0KPGRpdiBzdHlsZT0iZm9udC1zaXplOiAxMHB4OyBjb2xvcjogIzY2NjY2NjsgcGFkZGluZy10b3A6IDhweDsgYm9yZGVyLXRvcC1zdHlsZTogc29saWQ7IGJvcmRlci10b3AtY29sb3I6ICNkY2RjZGM7IGJvcmRlci10b3Atd2lkdGg6IDFweCI-DQogIDxwPsKpIDIwMTcgIEdvb2dsZSBJbmMuIDE2MDAgQW1waGl0aGVhdHJlIFBhcmt3YXksIE1vdW50YWluIFZpZXcsIENBIDk0MDQzPC9wPg0KDQogIDxwPjxpPllvdSBoYXZlIHJlY2VpdmVkIHRoaXMgdXBkYXRlIGFzIGEgRyBTdWl0ZSBzZXJ2aWNlIGFubm91bmNlbWVudC48L2k-PC9wPg0KPC9kaXY-DQo8aW1nIGhlaWdodD0iMSIgd2lkdGg9IjMiIHNyYz0iaHR0cHM6Ly93d3cuZ29vZ2xlLmNvbS9hcHBzZXJ2ZS9ta3QvaW1nL2xUUERhTG1XbHg1blNpbTF6OWp3RG1vTVYzSjRvMVZfcDhjPS5naWYiPg=="
}
}
]
And in above, the body of second element(partId 0.0 with mimeType text/html) looks like this:
"body": {
"size": 3112,
"data": "PCEtLSBUaGlzIGN...<trimmed for succintness>..cDhjPS5naWYiPg=="
}
So how do I decode this data ?.
The headers are as follow for above part(partId 0.1)
"headers": [
{
"name": "Content-Type",
"value": "text/html; charset=\"UTF-8\""
},
{
"name": "Content-Transfer-Encoding",
"value": "quoted-printable"
}
]
So the content-transfer-encoding is "quote-printable"
Same encrypted/encoded result is what I get when I fetch other email messages.
Not sure how do I decode the data from the body(neither could I find anywhere in the documentation about it).
I built something to handle this like this:
public string GetBodyWithRecursion(MessagePart p, string mimeType)
{
string Body = "";
if (p.parts.Parts != null)
{
foreach (MessagePart part in p.Parts)
{
Body = $"{Body} {GetBodyWithRecursion(part, mimeType)}";
}
}
else if (p.Body.Data != null && p.Body.AttachmentId == null && p.MimeType == mimeType)
{
Body = methodToConvertFrom64Url(p.Body.Data);
}
return Body;
}
I call this first with text/html and if this is blank - then with text/plain. Incase HTML is not available and only text is.
Hope this helps,
Mike

Resources