-
Notifications
You must be signed in to change notification settings - Fork 82
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
H-3166: Mimic Flow behavior in artillery #4771
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
diff --git a/node_modules/@artilleryio/int-commons/engine_util.js b/node_modules/@artilleryio/int-commons/engine_util.js | ||
index 8e5dc73..31a9a01 100644 | ||
--- a/node_modules/@artilleryio/int-commons/engine_util.js | ||
+++ b/node_modules/@artilleryio/int-commons/engine_util.js | ||
@@ -6,7 +6,6 @@ | ||
|
||
const async = require('async'); | ||
const debug = require('debug')('engine_util'); | ||
-const deepForEach = require('deep-for-each'); | ||
const espree = require('espree'); | ||
const L = require('lodash'); | ||
const vm = require('vm'); | ||
@@ -257,42 +256,36 @@ function template(o, context, inPlace) { | ||
} | ||
|
||
// Mutates the object in place | ||
-function templateObjectOrArray(o, context) { | ||
- deepForEach(o, (value, key, subj, path) => { | ||
- const newPath = template(path, context, true); | ||
- | ||
- let newValue; | ||
+function templateObject(o, context) { | ||
+ Object.entries(o).forEach(([key, value]) => { | ||
if (value && value.constructor !== Object && value.constructor !== Array) { | ||
- newValue = template(value, context, true); | ||
+ o[key] = template(o[key], context, true); | ||
} else { | ||
- newValue = value; | ||
- } | ||
- | ||
- debug( | ||
- `path = ${path} ; value = ${JSON.stringify( | ||
- value | ||
- )} (${typeof value}) ; (subj type: ${ | ||
- subj.length ? 'list' : 'hash' | ||
- }) ; newValue = ${JSON.stringify(newValue)} ; newPath = ${newPath}` | ||
- ); | ||
- | ||
- // If path has changed, we need to unset the original path and | ||
- // explicitly walk down the new subtree from this path: | ||
- if (path !== newPath) { | ||
- L.unset(o, path); | ||
- newValue = template(value, context, true); | ||
+ templateObjectOrArray(value, context); | ||
} | ||
+ }); | ||
+} | ||
|
||
- if (newPath.endsWith(key)) { | ||
- const keyIndex = newPath.lastIndexOf(key); | ||
- const prefix = newPath.substr(0, keyIndex - 1); | ||
- L.set(o, `${prefix}["${key}"]`, newValue); | ||
+// Mutates the array in place | ||
+function templateArray(o, context) { | ||
+ o.forEach((value, index) => { | ||
+ if (value && value.constructor !== Object && value.constructor !== Array) { | ||
+ o[index] = template(o[index], context, true); | ||
} else { | ||
- L.set(o, newPath, newValue); | ||
+ templateObjectOrArray(value, context); | ||
} | ||
}); | ||
} | ||
|
||
+// Mutates the object or array in place | ||
+function templateObjectOrArray(o, context) { | ||
+ if (o.constructor === Array) { | ||
+ templateArray(o, context); | ||
+ } else { | ||
+ templateObject(o, context); | ||
+ } | ||
+} | ||
+ | ||
function renderVariables(str, vars) { | ||
const RX = /{{{?[\s$\w\.\[\]\'\"-]+}}}?/g; | ||
let rxmatch; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
before: | ||
flow: | ||
- function: login | ||
|
||
scenarios: | ||
- name: Mimic a flow run | ||
beforeRequest: refreshSessionToken | ||
flow: | ||
- count: 10 | ||
loop: | ||
- post: | ||
name: Create entities | ||
url: / | ||
json: | ||
query: | | ||
mutation createEntity($ownedById: OwnedById!, $entityTypeId: VersionedUrl!, $properties: PropertyObjectWithMetadata!) { | ||
createEntity(ownedById: $ownedById, entityTypeId: $entityTypeId, properties: $properties) | ||
} | ||
variables: | ||
ownedById: "{{ session.ownedById }}" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not strictly needed but we have it available. |
||
entityTypeId: https://hash.ai/@hash/types/entity-type/usage-record/v/2 | ||
properties: | ||
value: | ||
https://hash.ai/@hash/types/property-type/input-unit-count/: | ||
value: 1000 | ||
metadata: | ||
dataTypeId: https://blockprotocol.org/@blockprotocol/types/data-type/number/v/1 | ||
https://hash.ai/@hash/types/property-type/output-unit-count/: | ||
value: 1000 | ||
metadata: | ||
dataTypeId: https://blockprotocol.org/@blockprotocol/types/data-type/number/v/1 | ||
expect: | ||
- notHasProperty: errors | ||
- post: | ||
name: Create entities | ||
url: http://127.0.0.1:4000/entities/bulk | ||
Comment on lines
+34
to
+36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I kept the graph endpoint to show how this is used |
||
headers: | ||
X-Authenticated-User-Actor-Id: "{{ session.ownedById }}" | ||
json: | ||
- ownedById: "{{ session.ownedById }}" | ||
entityTypeIds: | ||
- https://hash.ai/@hash/types/entity-type/usage-record/v/2 | ||
properties: | ||
value: | ||
https://hash.ai/@hash/types/property-type/input-unit-count/: | ||
value: 1000 | ||
metadata: | ||
dataTypeId: https://blockprotocol.org/@blockprotocol/types/data-type/number/v/1 | ||
https://hash.ai/@hash/types/property-type/output-unit-count/: | ||
value: 1000 | ||
metadata: | ||
dataTypeId: https://blockprotocol.org/@blockprotocol/types/data-type/number/v/1 | ||
draft: false | ||
relationships: | ||
- relation: setting | ||
subject: | ||
kind: setting | ||
subjectId: administratorFromWeb |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,63 +7,45 @@ import { extractOwnedByIdFromEntityId } from "@local/hash-subgraph"; | |
import { Configuration, FrontendApi } from "@ory/client"; | ||
|
||
import { getUserByKratosIdentityId } from "./graph"; | ||
import type { BeforeRequest, RequestParams } from "./types"; | ||
import type { ActionFn, BeforeRequestFn } from "./types"; | ||
|
||
const API_ORIGIN = "http://127.0.0.1:5001"; | ||
|
||
type LoginContext = { | ||
flowId: string; | ||
session: { | ||
token: string; | ||
expiresAt?: string; | ||
expiresAt?: number; | ||
user: SimpleProperties<User["properties"]>; | ||
ownedById: OwnedById; | ||
}; | ||
}; | ||
|
||
const setAuthorizationHeader = (request: RequestParams, token: string) => { | ||
if (!request.headers) { | ||
request.headers = {}; | ||
let __oryKratosClient: FrontendApi | undefined; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there a naming pattern we use for this? Or is there a better way? Generally I just tried to avoid creating the client multiple times. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd use one underscore ( |
||
const getOryKratosClient = () => { | ||
if (!__oryKratosClient) { | ||
__oryKratosClient = new FrontendApi( | ||
new Configuration({ | ||
basePath: `${API_ORIGIN}/auth`, | ||
baseOptions: { | ||
withCredentials: true, | ||
}, | ||
}), | ||
); | ||
} | ||
request.headers.Authorization = `Bearer ${token}`; | ||
}; | ||
|
||
export const refreshSessionToken: BeforeRequest<LoginContext> = async ( | ||
request, | ||
context, | ||
) => { | ||
if (context.vars.session) { | ||
if (context.vars.session.expiresAt) { | ||
if (context.vars.session.expiresAt > new Date().toISOString()) { | ||
setAuthorizationHeader(request, context.vars.session.token); | ||
return; | ||
} | ||
} else { | ||
setAuthorizationHeader(request, context.vars.session.token); | ||
return; | ||
} | ||
} | ||
|
||
const oryKratosClient = new FrontendApi( | ||
new Configuration({ | ||
basePath: `${API_ORIGIN}/auth`, | ||
baseOptions: { | ||
withCredentials: true, | ||
}, | ||
}), | ||
); | ||
return __oryKratosClient; | ||
}; | ||
|
||
if (!context.vars.flowId) { | ||
const loginFlow = await oryKratosClient | ||
.createNativeLoginFlow() | ||
.then(({ data }) => data); | ||
export const login: ActionFn<LoginContext> = async (context) => { | ||
const oryKratosClient = getOryKratosClient(); | ||
|
||
context.vars.flowId = loginFlow.id; | ||
} | ||
const loginFlow = await oryKratosClient | ||
.createNativeLoginFlow() | ||
.then(({ data }) => data); | ||
|
||
const fullLogin = await oryKratosClient | ||
.updateLoginFlow({ | ||
flow: context.vars.flowId, | ||
flow: loginFlow.id, | ||
updateLoginFlowBody: { | ||
method: "password", | ||
password_identifier: "email", | ||
|
@@ -86,9 +68,27 @@ export const refreshSessionToken: BeforeRequest<LoginContext> = async ( | |
|
||
context.vars.session = { | ||
token: fullLogin.session_token, | ||
expiresAt: fullLogin.session.expires_at, | ||
expiresAt: fullLogin.session.expires_at | ||
? new Date(fullLogin.session.expires_at).valueOf() | ||
: undefined, | ||
user: simplifyProperties(user.properties), | ||
ownedById: extractOwnedByIdFromEntityId(user.entityId), | ||
}; | ||
setAuthorizationHeader(request, context.vars.session.token); | ||
}; | ||
|
||
export const refreshSessionToken: BeforeRequestFn<LoginContext> = async ( | ||
request, | ||
context, | ||
events, | ||
) => { | ||
if ( | ||
!context.vars.session || | ||
(context.vars.session.expiresAt && | ||
context.vars.session.expiresAt < Date.now()) | ||
) { | ||
await login(context, events); | ||
} | ||
|
||
request.headers ??= {}; | ||
request.headers.Authorization = `Bearer ${context.vars.session!.token}`; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10163,15 +10163,6 @@ | |
resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-4.2.2.tgz#ed4e0ad92306a704f9fb132a0cfcf77486dbe2bc" | ||
integrity "sha1-7U4K2SMGpwT5+xMqDPz3dIbb4rw= sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==" | ||
|
||
"@types/[email protected]": | ||
version "1.7.4" | ||
resolved "https://registry.yarnpkg.com/@types/artillery/-/artillery-1.7.4.tgz#683140e7a0915a42377fd9ca6473ed09cf516ebb" | ||
integrity sha512-nqT0ixMaWyy8eVyvVLfbea/8q9TRnzO6UlpEVejTTy49YKUaax3KL/Pp/36BFkGL9c0WYc8Ea9Yhy7CahNnQBA== | ||
dependencies: | ||
"@types/node" "*" | ||
"@types/tough-cookie" "*" | ||
got "^11.8.5" | ||
|
||
"@types/babel__core@^7.0.0": | ||
version "7.1.20" | ||
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.20.tgz#e168cdd612c92a2d335029ed62ac94c95b362359" | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Accidentally committed this, but it doesn't hurt, either, as it's easier to extend π