Skip to content

Commit 7557002

Browse files
committed
add an example with k6 core oss apis vs new apis
1 parent a8f20f3 commit 7557002

File tree

1 file changed

+143
-23
lines changed

1 file changed

+143
-23
lines changed

src/data/markdown/docs/05 Examples/01 Examples/10 api-crud-operations.md

Lines changed: 143 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ title: 'API CRUD Operations'
33
excerpt: 'This example covers the usage of k6 to test a REST API CRUD operations.'
44
---
55

6-
The example showcases the testing of CRUD operations on a REST API.
6+
The examples showcase the testing of CRUD operations on a REST API.
77

88
CRUD refers to the basic operations in a database: Create, Read, Update, and Delete. We can map these operations to HTTP methods in REST APIs:
99

@@ -12,6 +12,8 @@ CRUD refers to the basic operations in a database: Create, Read, Update, and Del
1212
- _Update_: HTTP `PUT`or `PATCH` to change an existing resource.
1313
- _Delete_: HTTP `DELETE` to remove a resource.
1414

15+
You'll find two test examples: the first one uses the core k6 APIs (`k6/http` and `checks`), and the second showcases more recent APIs (`httpx` and `k6chaijs`).
16+
1517
## Test steps
1618

1719
In the [setup() stage](/using-k6/test-lifecycle/#setup-and-teardown-stages) we create a user for the [k6 HTTP REST API](https://test-api.k6.io/). We then retrieve and return a bearer token to authenticate the next CRUD requests.
@@ -23,12 +25,11 @@ The steps implemented in the [VU stage](/using-k6/test-lifecycle/#the-vu-stage)
2325
3. _Update_ the name of the "croc" and _read_ the "croc" to confirm the update operation.
2426
4. _Delete_ the "croc" resource.
2527

26-
<CodeGroup labels={["api-crud-operations.js"]} lineNumbers={[true]}>
28+
<CodeGroup labels={["api-crud-operations-k6-core-apis.js"]} lineNumbers={[true]}>
2729

2830
```javascript
29-
import { describe, expect } from 'https://jslib.k6.io/k6chaijs/4.3.4.3/index.js';
30-
import { Httpx } from 'https://jslib.k6.io/httpx/0.1.0/index.js';
31-
import { randomIntBetween, randomItem } from "https://jslib.k6.io/k6-utils/1.2.0/index.js";
31+
import http from 'k6/http';
32+
import { check, group, fail } from 'k6';
3233

3334
export const options = {
3435
thresholds: {
@@ -43,11 +44,6 @@ export const options = {
4344
iterations: 1
4445
};
4546

46-
const USERNAME = `user${randomIntBetween(1, 100000)}@example.com`; // Set your own email;
47-
const PASSWORD = 'superCroc2019';
48-
49-
const session = new Httpx({ baseURL: 'https://test-api.k6.io' });
50-
5147
// Create a random string of given length
5248
function randomString(length, charset = '') {
5349
if (!charset) charset = 'abcdefghijklmnopqrstuvwxyz';
@@ -56,7 +52,131 @@ function randomString(length, charset = '') {
5652
return res;
5753
}
5854

59-
// Authenticate user and retrieve authentication token for the API requests
55+
const USERNAME = `${randomString(10)}@example.com`; // Set your own email or `${randomString(10)}@example.com`;
56+
const PASSWORD = 'superCroc2019';
57+
58+
const BASE_URL = 'https://test-api.k6.io';
59+
60+
// Register a new user and retrieve authentication token for subsequent API requests
61+
export function setup() {
62+
const res = http.post(`${BASE_URL}/user/register/`, {
63+
first_name: 'Crocodile',
64+
last_name: 'Owner',
65+
username: USERNAME,
66+
password: PASSWORD,
67+
});
68+
69+
check(res, { 'created user': (r) => r.status === 201 });
70+
71+
const loginRes = http.post(`${BASE_URL}/auth/token/login/`, {
72+
username: USERNAME,
73+
password: PASSWORD,
74+
});
75+
76+
const authToken = loginRes.json('access');
77+
check(authToken, { 'logged in successfully': () => authToken !== '' });
78+
79+
return authToken;
80+
}
81+
82+
export default (authToken) => {
83+
// set the authorization header on the session for the subsequent requests
84+
const requestConfigWithTag = (tag) => ({
85+
headers: {
86+
Authorization: `Bearer ${authToken}`,
87+
},
88+
tags: Object.assign(
89+
{},
90+
{
91+
name: 'PrivateCrocs',
92+
},
93+
tag
94+
),
95+
});
96+
97+
let URL = `${BASE_URL}/my/crocodiles/`;
98+
99+
group('01. Create a new crocodile', () => {
100+
const payload = {
101+
name: `Name ${randomString(10)}`,
102+
sex: 'F',
103+
date_of_birth: '2023-05-11',
104+
};
105+
106+
const res = http.post(URL, payload, requestConfigWithTag({ name: 'Create' }));
107+
108+
if (check(res, { 'Croc created correctly': (r) => r.status === 201 })) {
109+
URL = `${URL}${res.json('id')}/`;
110+
} else {
111+
console.log(`Unable to create a Croc ${res.status} ${res.body}`);
112+
return;
113+
}
114+
});
115+
116+
group('02. Fetch private crocs', () => {
117+
const res = http.get(`${BASE_URL}/my/crocodiles/`, requestConfigWithTag({ name: 'Fetch' }));
118+
check(res, { 'retrieved crocs status': (r) => r.status === 200 });
119+
check(res.json(), { 'retrieved crocs list': (r) => r.length > 0 });
120+
});
121+
122+
group('03. Update the croc', () => {
123+
const payload = { name: 'New name' };
124+
const res = http.patch(URL, payload, requestConfigWithTag({ name: 'Update' }));
125+
const isSuccessfulUpdate = check(res, {
126+
'Update worked': () => res.status === 200,
127+
'Updated name is correct': () => res.json('name') === 'New name',
128+
});
129+
130+
if (!isSuccessfulUpdate) {
131+
console.log(`Unable to update the croc ${res.status} ${res.body}`);
132+
return;
133+
}
134+
});
135+
136+
group('04. Delete the croc', () => {
137+
const delRes = http.del(URL, null, requestConfigWithTag({ name: 'Delete' }));
138+
139+
const isSuccessfulDelete = check(null, {
140+
'Croc was deleted correctly': () => delRes.status === 204,
141+
});
142+
143+
if (!isSuccessfulDelete) {
144+
console.log(`Croc was not deleted properly`);
145+
return;
146+
}
147+
});
148+
149+
};
150+
```
151+
152+
</CodeGroup>
153+
154+
<CodeGroup labels={["api-crud-operations-k6-new-apis.js"]} lineNumbers={[true]}>
155+
156+
```javascript
157+
import { describe, expect } from 'https://jslib.k6.io/k6chaijs/4.3.4.3/index.js';
158+
import { Httpx } from 'https://jslib.k6.io/httpx/0.1.0/index.js';
159+
import { randomIntBetween, randomItem, randomString } from "https://jslib.k6.io/k6-utils/1.2.0/index.js";
160+
161+
export const options = {
162+
thresholds: {
163+
checks: [{
164+
threshold: 'rate == 1.00', abortOnFail: true,
165+
}],
166+
'http_req_duration': ['p(90)<25000', 'p(95)<30000'],
167+
'http_req_duration{name:Create}': ['avg<15000', 'max<25000'],
168+
},
169+
// for the example, let's run only 1 VU with 1 iteration
170+
vus: 1,
171+
iterations: 1,
172+
};
173+
174+
const USERNAME = `user${randomIntBetween(1, 100000)}@example.com`; // Set your own email;
175+
const PASSWORD = 'superCroc2019';
176+
177+
const session = new Httpx({ baseURL: 'https://test-api.k6.io' });
178+
179+
// Register a new user and retrieve authentication token for subsequent API requests
60180
export function setup() {
61181

62182
let authToken = null;
@@ -70,7 +190,7 @@ export function setup() {
70190
});
71191

72192
expect(resp.status, 'User create status').to.equal(201);
73-
expect(resp).to.have.validJsonBody();
193+
expect(resp, 'User create valid json response').to.have.validJsonBody();
74194
});
75195

76196
describe(`setup - Authenticate the new user ${USERNAME}`, () => {
@@ -79,18 +199,18 @@ export function setup() {
79199
password: PASSWORD
80200
});
81201

82-
expect(resp.status, 'Auth status').to.equal(200);
83-
expect(resp).to.have.validJsonBody();
202+
expect(resp.status, 'Authenticate status').to.equal(200);
203+
expect(resp, 'Authenticate valid json response').to.have.validJsonBody();
84204
authToken = resp.json('access');
85-
expect(authToken, 'auth token').to.not.be.null;
205+
expect(authToken, 'Authentication token', 'auth token').to.not.be.null;
86206
});
87207

88208
return authToken;
89209
}
90210

91211
export default function (authToken) {
92212

93-
// set the authorization header on the session for the subsequent requests.
213+
// set the authorization header on the session for the subsequent requests
94214
session.addHeader('Authorization', `Bearer ${authToken}`);
95215

96216
describe('01. Create a new crocodile', (t) => {
@@ -104,7 +224,7 @@ export default function (authToken) {
104224
const resp = session.post(`/my/crocodiles/`, payload);
105225

106226
expect(resp.status, 'Croc creation status').to.equal(201);
107-
expect(resp).to.have.validJsonBody();
227+
expect(resp, 'Croc creation valid json response').to.have.validJsonBody();
108228

109229
session.newCrocId = resp.json('id');
110230
})
@@ -115,8 +235,8 @@ export default function (authToken) {
115235
const resp = session.get('/my/crocodiles/');
116236

117237
expect(resp.status, 'Fetch croc status').to.equal(200);
118-
expect(resp).to.have.validJsonBody();
119-
expect(resp.json().length, 'number of crocs').to.be.above(0);
238+
expect(resp, 'Fetch croc valid json response').to.have.validJsonBody();
239+
expect(resp.json().length, 'Number of crocs').to.be.above(0);
120240
})
121241

122242
describe('03. Update the croc', (t) => {
@@ -127,15 +247,15 @@ export default function (authToken) {
127247
const resp = session.patch(`/my/crocodiles/${session.newCrocId}/`, payload);
128248

129249
expect(resp.status, 'Croc patch status').to.equal(200);
130-
expect(resp).to.have.validJsonBody();
131-
expect(resp.json('name')).to.equal(payload.name);
250+
expect(resp, 'Fetch croc valid json response').to.have.validJsonBody();
251+
expect(resp.json('name'), 'Croc name').to.equal(payload.name);
132252

133253
// read "croc" again to verify the update worked
134254
const resp1 = session.get(`/my/crocodiles/${session.newCrocId}/`);
135255

136256
expect(resp1.status, 'Croc fetch status').to.equal(200);
137-
expect(resp1).to.have.validJsonBody();
138-
expect(resp1.json('name')).to.equal(payload.name);
257+
expect(resp1, 'Fetch croc valid json response').to.have.validJsonBody();
258+
expect(resp1.json('name'), 'Croc name').to.equal(payload.name);
139259

140260
})
141261

0 commit comments

Comments
 (0)