Skip to content

Commit

Permalink
Signups working
Browse files Browse the repository at this point in the history
  • Loading branch information
wilwade committed Aug 6, 2024
1 parent a9b3da4 commit ca82730
Show file tree
Hide file tree
Showing 7 changed files with 1,131 additions and 28 deletions.
6 changes: 6 additions & 0 deletions services/account/k6-test/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,9 @@ To run the script, execute the following command:
```bash
k6 run health-check.k6.js
```

## Generating Test Data

So that k6 doesn't have to interact with the chain, we can generate data sepatately and then use it for the tests.

`npm run generate:signup` for example will re-generate the `signups.gen.js` file with 100 generated valid signup payloads.
26 changes: 26 additions & 0 deletions services/account/k6-test/generate/helpers/chain.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Only way to silence PolkadotJS API warnings we don't want
console.warn = () => {};

import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';
import { mnemonicGenerate } from '@polkadot/util-crypto';
import { u8aToHex, u8aWrapBytes } from '@polkadot/util';

export async function getApi() {
const api = await ApiPromise.create({
// Using mainnet as: 1. Nothing here would use local only metadata, 2. We aren't actually submitting.
provider: new WsProvider('wss://0.rpc.frequency.xyz'),
});
await api.isReady;
return api;
}

export function createKey() {
const mnemonic = mnemonicGenerate();
const keyring = new Keyring({ type: 'sr25519' });
const keypair = keyring.createFromUri(mnemonic);
return keypair;
}

export function signPayloadSr25519(keys, data) {
return { Sr25519: u8aToHex(keys.sign(u8aWrapBytes(data.toU8a()))) };
}
69 changes: 69 additions & 0 deletions services/account/k6-test/generate/signups.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import fs from 'fs/promises';
import { Bytes } from '@polkadot/types';
import { getApi, createKey, signPayloadSr25519 } from './helpers/chain.mjs';

const GENERATE_COUNT = 10;

const signup = (api) => {
const keypair = createKey();
const expiration = 100; // Will this fail when running against longer chains?

const addProviderData = api.registry.createType('PalletMsaAddProvider', {
authorizedMsaId: 1,
schemaIds: [1],
expiration,
});
const createTx = api.tx.msa.createSponsoredAccountWithDelegation(
keypair.address,
signPayloadSr25519(keypair, addProviderData),
addProviderData,
);
const claimHandlePayload = api.registry.createType('CommonPrimitivesHandlesClaimHandlePayload', {
baseHandle: new Bytes(api.registry, keypair.address.substring(0, 8)),
expiration,
});
const claimTx = api.tx.handles.claimHandle(
keypair.address,
signPayloadSr25519(keypair, claimHandlePayload),
claimHandlePayload,
);

return {
signUp: {
extrinsics: [
{
pallet: 'msa',
extrinsicName: 'createSponsoredAccountWithDelegation',
encodedExtrinsic: createTx.toHex(),
},
{
pallet: 'handles',
extrinsicName: 'claimHandle',
encodedExtrinsic: claimTx.toHex(),
},
],
},
};
};

const main = async () => {
const api = await getApi();
const generated = [];
for (let i = 0; i < GENERATE_COUNT; i++) {
generated.push(signup(api));
}
// Write the generated array to './signups.gen.js'
const fileContent = `
// GENERATED FILE! Regenerate using npm run generate:signups
export const signups = ${JSON.stringify(generated, null, 2)};
`;

try {
await fs.writeFile('./signups.gen.js', fileContent, 'utf8');
console.log('Successfully wrote to ./signups.gen.js');
} catch (err) {
console.error('Error writing to file:', err);
}
};

main().catch(console.error).finally(process.exit);
45 changes: 17 additions & 28 deletions services/account/k6-test/new-sign-up.k6.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
/* eslint-disable func-names */
/*
* Account Service
* Account Service API
* Account Service API: New Sign Ups
* NOTE: This test MUST run on a clean chain and cannot be re-run without running: npm run generate:signups
*
* OpenAPI spec version: 1.0
*
Expand All @@ -14,6 +15,8 @@

import http from 'k6/http';
import { group, check, sleep } from 'k6';
import exec from 'k6/execution';
import { signups } from './signups.gen.js';

export const options = {
// scenarios: {
Expand All @@ -27,7 +30,6 @@ export const options = {
// },
// },
vus: 1,
iterations: 1, // TODO: Make the extrinsics dynamic to run this more than once on the same chain!
duration: '20s',
thresholds: {
http_req_duration: ['avg<100', 'p(95)<200'],
Expand All @@ -44,22 +46,22 @@ const CALLBACK_URL = 'http://localhost:3001/webhooks/account-service';
const BASE_URL = 'http://localhost:3000';
// Sleep duration between successive requests.
const SLEEP_DURATION = 0.1;
const BLOCKTIME_SECONDS = 12;
const BLOCKTIME_SECONDS = 13; // Add 1 second for additional loop buffer
// Global variables should be initialized.

function checkCallback() {
function checkCallback(referenceId) {
const res = http.get(CALLBACK_URL);
console.log('Callback response:', res.status, res.body);
check(res, {
'callback received': (r) => r.status === 201,
'callback contains expected data': (r) => {
const json = JSON.parse(r.body);
return json.referenceId === 'DekKx1F_WYOWCQFXE3vgwqXP4U4';
return json.referenceId === referenceId;
},
});
}

export function setup() {
export async function setup() {
// Let's make sure the service is healthy before starting the test.
console.log('Checking service health...');
const res = http.get(`${BASE_URL}/healthz`);
Expand All @@ -68,10 +70,11 @@ export function setup() {
console.error('Service is not healthy! Terminating test...');
return false;
}
return true;

return { signUpBody: signups[exec.vu.iterationInInstance] };
}

export default function () {
export default function (setupData) {
group('/v1/accounts/siwf', () => {
// Request No. 1: AccountsController_getSIWFConfig
{
Expand All @@ -86,39 +89,25 @@ export default function () {
}

// Request No. 2: AccountsController_postSignInWithFrequency
let referenceId;
{
const url = `${BASE_URL}/v1/accounts/siwf`;
// Use the SIWF sample Sign Up request body for a new user.
const body = {
signUp: {
extrinsics: [
{
pallet: 'msa',
extrinsicName: 'createSponsoredAccountWithDelegation',
encodedExtrinsic:
'0xed01043c01b01b4dcafc8a8e73bff98e7558249f53cd0e0e64fa6b8f0159f0913d4874d9360176644186458bad3b00bbd0ac21e6c9bd5a8bed9ced7a772d11a9aac025b47f6559468808e272696f596a02af230951861027c0dc30f7163ecf316838a0723483010000000000000014000000000000000000004d000000',
},
{
pallet: 'handles',
extrinsicName: 'claimHandle',
encodedExtrinsic:
'0xb901044200b01b4dcafc8a8e73bff98e7558249f53cd0e0e64fa6b8f0159f0913d4874d93601225508ae2da9804c60660a150277eb32b2a0f6b9c8f6e07dd6cad799cb31ae1dfb43896f488e9c0b7ec8b530d930b3f9b690683f2765d5def3fee3fc6540d58714656e6464794d000000',
},
],
},
};
const body = setupData.signUpBody;
const params = { headers: { 'Content-Type': 'application/json', Accept: 'application/json' } };
const request = http.post(url, JSON.stringify(body), params);

check(request, {
'Signed in successfully': (r) => r.status === 201,
'Has referenceId': (r) => !!JSON.parse(r.body).referenceId,
});
referenceId = JSON.parse(request.body).referenceId;
}

// The front end will poll the server for the account status.
// We'll wait here for a block to be finalized.
sleep(BLOCKTIME_SECONDS);
console.log('Block finalized. Checking callback...');
checkCallback();
console.log('Block finalized. Checking callback...', { referenceId });
checkCallback(referenceId);
});
}
Loading

0 comments on commit ca82730

Please sign in to comment.