Initial commit
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 59 KiB |
@@ -0,0 +1,45 @@
|
|||||||
|
version: "3.8"
|
||||||
|
networks:
|
||||||
|
k6:
|
||||||
|
grafana:
|
||||||
|
services:
|
||||||
|
influxdb:
|
||||||
|
image: influxdb:latest
|
||||||
|
networks:
|
||||||
|
- k6
|
||||||
|
- grafana
|
||||||
|
ports:
|
||||||
|
- "8086:8086"
|
||||||
|
environment:
|
||||||
|
- INFLUXDB_DB=k6
|
||||||
|
grafana:
|
||||||
|
image: grafana/grafana:latest
|
||||||
|
networks:
|
||||||
|
- grafana
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
environment:
|
||||||
|
- GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
|
||||||
|
- GF_AUTH_ANONYMOUS_ENABLED=true
|
||||||
|
- GF_AUTH_BASIC_ENABLED=false
|
||||||
|
volumes:
|
||||||
|
- ./shared/grafana:/etc/grafana/provisioning/
|
||||||
|
simulado:
|
||||||
|
image : ldabiralai/simulado:latest
|
||||||
|
networks:
|
||||||
|
- k6
|
||||||
|
ports:
|
||||||
|
- "3001:80"
|
||||||
|
volumes:
|
||||||
|
- ./shared/simulado:/app
|
||||||
|
command: ./bin/simulado -f /app/mocks.json
|
||||||
|
k6:
|
||||||
|
image: loadimpact/k6:latest
|
||||||
|
networks:
|
||||||
|
- k6
|
||||||
|
ports:
|
||||||
|
- "6565:6565"
|
||||||
|
volumes:
|
||||||
|
- ./shared/k6:/scripts
|
||||||
|
environment:
|
||||||
|
- K6_OUT=influxdb=http://influxdb:8086/k6
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
openapi: 3.0.0
|
||||||
|
info:
|
||||||
|
title: existingApis
|
||||||
|
version: '1.0'
|
||||||
|
servers:
|
||||||
|
- url: 'http://localhost:3001'
|
||||||
|
paths:
|
||||||
|
'/product/{productId}/similarids':
|
||||||
|
parameters:
|
||||||
|
- schema:
|
||||||
|
type: string
|
||||||
|
name: productId
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
get:
|
||||||
|
operationId: get-product-similarids
|
||||||
|
summary: Gets the ids of the similar products
|
||||||
|
description: Returns the similar products to a given one ordered by similarity
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: OK
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
description: List of productIds similar to a given one ordered by similarity
|
||||||
|
minItems: 0
|
||||||
|
uniqueItems: true
|
||||||
|
items:
|
||||||
|
type: integer
|
||||||
|
'/product/{productId}':
|
||||||
|
parameters:
|
||||||
|
- schema:
|
||||||
|
type: string
|
||||||
|
name: productId
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
get:
|
||||||
|
operationId: get-product-productId
|
||||||
|
summary: Gets a product detail
|
||||||
|
description: Returns the product detail for a given productId
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: OK
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
description: 'Product detail'
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
minLength: 1
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
minLength: 1
|
||||||
|
price:
|
||||||
|
type: number
|
||||||
|
availability:
|
||||||
|
type: boolean
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- name
|
||||||
|
- price
|
||||||
|
- availability
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
# Backend dev technical test
|
||||||
|
We want to offer a new feature to our customers showing similar products to the one they are browsing. To do this we agreed with out front end applications to create a new REST API that will provide them the product detail of the similar products to a given one. [Here](./similarProducts.yaml) is the contract we agreed.
|
||||||
|
|
||||||
|
We already have an endpoint that provides the product Ids similar to a given one. We also have another endpoint that returns the product detail by productId. [Here](./existingApis.yaml) is the documentation of the existing APIs.
|
||||||
|
|
||||||
|
**Create a Spring boot application that exposes the agreed REST API on port 5000.**
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Note that _Test_ and _Mocks_ components are given, you must only implement _yourApp_.
|
||||||
|
|
||||||
|
## Testing and Self-evaluation
|
||||||
|
You can run the same test we will put through your application. You just need to have docker installed.
|
||||||
|
|
||||||
|
First of all you may need to enable file sharing for the `shared` folder on your docker dashboard -> settings -> resources -> file sharing.
|
||||||
|
|
||||||
|
Then you can start the mocks and other needed infrastructure with the following command.
|
||||||
|
```
|
||||||
|
docker-compose up -d simulado influxdb grafana
|
||||||
|
```
|
||||||
|
Check that mocks are working with a sample request to [http://localhost:3001/product/1/similarids](http://localhost:3001/product/1/similarids).
|
||||||
|
|
||||||
|
To execute the test run:
|
||||||
|
```
|
||||||
|
docker-compose run --rm k6 run scripts/test.js
|
||||||
|
```
|
||||||
|
Browse [http://localhost:3000/d/Le2Ku9NMk/k6-performance-test](http://localhost:3000/d/Le2Ku9NMk/k6-performance-test) to view the results.
|
||||||
|
|
||||||
|
## Evaluation
|
||||||
|
The following topics will be considered:
|
||||||
|
- Code clarity and maintainability
|
||||||
|
- Performance
|
||||||
|
- Resilence
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
apiVersion: 1
|
||||||
|
|
||||||
|
providers:
|
||||||
|
- name: 'myinfluxdb'
|
||||||
|
orgId: 1
|
||||||
|
folder: ''
|
||||||
|
type: file
|
||||||
|
disableDeletion: false
|
||||||
|
editable: true
|
||||||
|
options:
|
||||||
|
path: /etc/grafana/provisioning/dashboards
|
||||||
@@ -0,0 +1,444 @@
|
|||||||
|
{
|
||||||
|
"annotations": {
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"builtIn": 1,
|
||||||
|
"datasource": "-- Grafana --",
|
||||||
|
"enable": true,
|
||||||
|
"hide": true,
|
||||||
|
"iconColor": "rgba(0, 211, 255, 1)",
|
||||||
|
"name": "Annotations & Alerts",
|
||||||
|
"type": "dashboard"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"editable": true,
|
||||||
|
"gnetId": null,
|
||||||
|
"graphTooltip": 0,
|
||||||
|
"links": [],
|
||||||
|
"panels": [
|
||||||
|
{
|
||||||
|
"aliasColors": {},
|
||||||
|
"bars": false,
|
||||||
|
"dashLength": 10,
|
||||||
|
"dashes": false,
|
||||||
|
"datasource": null,
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"custom": {}
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"fill": 1,
|
||||||
|
"fillGradient": 0,
|
||||||
|
"gridPos": {
|
||||||
|
"h": 8,
|
||||||
|
"w": 24,
|
||||||
|
"x": 0,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
"hiddenSeries": false,
|
||||||
|
"id": 5,
|
||||||
|
"legend": {
|
||||||
|
"avg": false,
|
||||||
|
"current": false,
|
||||||
|
"max": false,
|
||||||
|
"min": false,
|
||||||
|
"rightSide": false,
|
||||||
|
"show": true,
|
||||||
|
"total": false,
|
||||||
|
"values": false
|
||||||
|
},
|
||||||
|
"lines": true,
|
||||||
|
"linewidth": 1,
|
||||||
|
"nullPointMode": "null",
|
||||||
|
"options": {
|
||||||
|
"alertThreshold": true
|
||||||
|
},
|
||||||
|
"percentage": false,
|
||||||
|
"pluginVersion": "7.3.6",
|
||||||
|
"pointradius": 2,
|
||||||
|
"points": false,
|
||||||
|
"renderer": "flot",
|
||||||
|
"seriesOverrides": [],
|
||||||
|
"spaceLength": 10,
|
||||||
|
"stack": false,
|
||||||
|
"steppedLine": false,
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"groupBy": [
|
||||||
|
{
|
||||||
|
"params": [
|
||||||
|
"1s"
|
||||||
|
],
|
||||||
|
"type": "time"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"params": [
|
||||||
|
"scenario"
|
||||||
|
],
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"params": [
|
||||||
|
"status"
|
||||||
|
],
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"params": [
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"type": "fill"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"measurement": "http_reqs",
|
||||||
|
"orderByTime": "ASC",
|
||||||
|
"policy": "default",
|
||||||
|
"refId": "A",
|
||||||
|
"resultFormat": "time_series",
|
||||||
|
"select": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"params": [
|
||||||
|
"value"
|
||||||
|
],
|
||||||
|
"type": "field"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"params": [],
|
||||||
|
"type": "count"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"tags": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"thresholds": [],
|
||||||
|
"timeFrom": null,
|
||||||
|
"timeRegions": [],
|
||||||
|
"timeShift": null,
|
||||||
|
"title": "Requests",
|
||||||
|
"tooltip": {
|
||||||
|
"shared": true,
|
||||||
|
"sort": 0,
|
||||||
|
"value_type": "individual"
|
||||||
|
},
|
||||||
|
"type": "graph",
|
||||||
|
"xaxis": {
|
||||||
|
"buckets": null,
|
||||||
|
"mode": "time",
|
||||||
|
"name": null,
|
||||||
|
"show": true,
|
||||||
|
"values": []
|
||||||
|
},
|
||||||
|
"yaxes": [
|
||||||
|
{
|
||||||
|
"$$hashKey": "object:671",
|
||||||
|
"format": "short",
|
||||||
|
"label": null,
|
||||||
|
"logBase": 1,
|
||||||
|
"max": null,
|
||||||
|
"min": null,
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$$hashKey": "object:672",
|
||||||
|
"format": "short",
|
||||||
|
"label": null,
|
||||||
|
"logBase": 1,
|
||||||
|
"max": null,
|
||||||
|
"min": null,
|
||||||
|
"show": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"yaxis": {
|
||||||
|
"align": false,
|
||||||
|
"alignLevel": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"aliasColors": {},
|
||||||
|
"bars": true,
|
||||||
|
"dashLength": 10,
|
||||||
|
"dashes": false,
|
||||||
|
"datasource": "myinfluxdb",
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"custom": {},
|
||||||
|
"links": []
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"fill": 1,
|
||||||
|
"fillGradient": 0,
|
||||||
|
"gridPos": {
|
||||||
|
"h": 7,
|
||||||
|
"w": 24,
|
||||||
|
"x": 0,
|
||||||
|
"y": 8
|
||||||
|
},
|
||||||
|
"hiddenSeries": false,
|
||||||
|
"id": 2,
|
||||||
|
"legend": {
|
||||||
|
"avg": false,
|
||||||
|
"current": false,
|
||||||
|
"max": false,
|
||||||
|
"min": false,
|
||||||
|
"rightSide": false,
|
||||||
|
"show": true,
|
||||||
|
"total": false,
|
||||||
|
"values": false
|
||||||
|
},
|
||||||
|
"lines": true,
|
||||||
|
"linewidth": 1,
|
||||||
|
"nullPointMode": "null",
|
||||||
|
"options": {
|
||||||
|
"alertThreshold": true
|
||||||
|
},
|
||||||
|
"percentage": false,
|
||||||
|
"pluginVersion": "7.3.6",
|
||||||
|
"pointradius": 1,
|
||||||
|
"points": true,
|
||||||
|
"renderer": "flot",
|
||||||
|
"seriesOverrides": [],
|
||||||
|
"spaceLength": 10,
|
||||||
|
"stack": false,
|
||||||
|
"steppedLine": true,
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"groupBy": [
|
||||||
|
{
|
||||||
|
"params": [
|
||||||
|
"1s"
|
||||||
|
],
|
||||||
|
"type": "time"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"measurement": "http_req_duration",
|
||||||
|
"orderByTime": "ASC",
|
||||||
|
"policy": "default",
|
||||||
|
"query": "SELECT mean(\"value\") FROM \"http_req_duration\" WHERE $timeFilter GROUP BY time($__interval) fill(null)",
|
||||||
|
"rawQuery": false,
|
||||||
|
"refId": "A",
|
||||||
|
"resultFormat": "time_series",
|
||||||
|
"select": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"params": [
|
||||||
|
"value"
|
||||||
|
],
|
||||||
|
"type": "field"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"params": [],
|
||||||
|
"type": "mean"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"tags": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"thresholds": [],
|
||||||
|
"timeFrom": null,
|
||||||
|
"timeRegions": [],
|
||||||
|
"timeShift": null,
|
||||||
|
"title": "http-req duration",
|
||||||
|
"tooltip": {
|
||||||
|
"shared": true,
|
||||||
|
"sort": 0,
|
||||||
|
"value_type": "individual"
|
||||||
|
},
|
||||||
|
"type": "graph",
|
||||||
|
"xaxis": {
|
||||||
|
"buckets": null,
|
||||||
|
"mode": "time",
|
||||||
|
"name": null,
|
||||||
|
"show": true,
|
||||||
|
"values": []
|
||||||
|
},
|
||||||
|
"yaxes": [
|
||||||
|
{
|
||||||
|
"$$hashKey": "object:543",
|
||||||
|
"format": "short",
|
||||||
|
"label": null,
|
||||||
|
"logBase": 1,
|
||||||
|
"max": null,
|
||||||
|
"min": null,
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$$hashKey": "object:544",
|
||||||
|
"format": "short",
|
||||||
|
"label": null,
|
||||||
|
"logBase": 1,
|
||||||
|
"max": null,
|
||||||
|
"min": null,
|
||||||
|
"show": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"yaxis": {
|
||||||
|
"align": false,
|
||||||
|
"alignLevel": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"aliasColors": {},
|
||||||
|
"bars": true,
|
||||||
|
"dashLength": 10,
|
||||||
|
"dashes": false,
|
||||||
|
"datasource": "myinfluxdb",
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"custom": {},
|
||||||
|
"links": []
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"fill": 3,
|
||||||
|
"fillGradient": 0,
|
||||||
|
"gridPos": {
|
||||||
|
"h": 9,
|
||||||
|
"w": 24,
|
||||||
|
"x": 0,
|
||||||
|
"y": 15
|
||||||
|
},
|
||||||
|
"hiddenSeries": false,
|
||||||
|
"id": 3,
|
||||||
|
"legend": {
|
||||||
|
"avg": false,
|
||||||
|
"current": false,
|
||||||
|
"max": false,
|
||||||
|
"min": false,
|
||||||
|
"show": true,
|
||||||
|
"total": false,
|
||||||
|
"values": false
|
||||||
|
},
|
||||||
|
"lines": true,
|
||||||
|
"linewidth": 1,
|
||||||
|
"nullPointMode": "null",
|
||||||
|
"options": {
|
||||||
|
"alertThreshold": true
|
||||||
|
},
|
||||||
|
"percentage": false,
|
||||||
|
"pluginVersion": "7.3.6",
|
||||||
|
"pointradius": 1,
|
||||||
|
"points": true,
|
||||||
|
"renderer": "flot",
|
||||||
|
"seriesOverrides": [],
|
||||||
|
"spaceLength": 10,
|
||||||
|
"stack": false,
|
||||||
|
"steppedLine": false,
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"groupBy": [
|
||||||
|
{
|
||||||
|
"params": [
|
||||||
|
"1s"
|
||||||
|
],
|
||||||
|
"type": "time"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"params": [
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"type": "fill"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"measurement": "vus",
|
||||||
|
"orderByTime": "ASC",
|
||||||
|
"policy": "default",
|
||||||
|
"query": "SELECT mean(\"value\") FROM \"http_req_duration\" WHERE $timeFilter GROUP BY time($__interval) fill(null)",
|
||||||
|
"rawQuery": false,
|
||||||
|
"refId": "A",
|
||||||
|
"resultFormat": "time_series",
|
||||||
|
"select": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"params": [
|
||||||
|
"value"
|
||||||
|
],
|
||||||
|
"type": "field"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"params": [],
|
||||||
|
"type": "mean"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"tags": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"thresholds": [],
|
||||||
|
"timeFrom": null,
|
||||||
|
"timeRegions": [],
|
||||||
|
"timeShift": null,
|
||||||
|
"title": "vus",
|
||||||
|
"tooltip": {
|
||||||
|
"shared": true,
|
||||||
|
"sort": 0,
|
||||||
|
"value_type": "individual"
|
||||||
|
},
|
||||||
|
"type": "graph",
|
||||||
|
"xaxis": {
|
||||||
|
"buckets": null,
|
||||||
|
"mode": "time",
|
||||||
|
"name": null,
|
||||||
|
"show": true,
|
||||||
|
"values": []
|
||||||
|
},
|
||||||
|
"yaxes": [
|
||||||
|
{
|
||||||
|
"$$hashKey": "object:309",
|
||||||
|
"format": "short",
|
||||||
|
"label": null,
|
||||||
|
"logBase": 1,
|
||||||
|
"max": null,
|
||||||
|
"min": null,
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$$hashKey": "object:310",
|
||||||
|
"format": "short",
|
||||||
|
"label": null,
|
||||||
|
"logBase": 1,
|
||||||
|
"max": null,
|
||||||
|
"min": null,
|
||||||
|
"show": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"yaxis": {
|
||||||
|
"align": false,
|
||||||
|
"alignLevel": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"refresh": false,
|
||||||
|
"schemaVersion": 26,
|
||||||
|
"style": "dark",
|
||||||
|
"tags": [],
|
||||||
|
"templating": {
|
||||||
|
"list": []
|
||||||
|
},
|
||||||
|
"time": {
|
||||||
|
"from": "now-30m",
|
||||||
|
"to": "now"
|
||||||
|
},
|
||||||
|
"timepicker": {
|
||||||
|
"refresh_intervals": [
|
||||||
|
"10s",
|
||||||
|
"30s",
|
||||||
|
"1m",
|
||||||
|
"5m",
|
||||||
|
"15m",
|
||||||
|
"30m",
|
||||||
|
"1h",
|
||||||
|
"2h",
|
||||||
|
"1d"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"timezone": "",
|
||||||
|
"title": "k6 performance test",
|
||||||
|
"uid": "Le2Ku9NMk",
|
||||||
|
"version": 1
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
apiVersion: 1
|
||||||
|
|
||||||
|
datasources:
|
||||||
|
- name: myinfluxdb
|
||||||
|
type: influxdb
|
||||||
|
access: proxy
|
||||||
|
database: k6
|
||||||
|
orgId: 1
|
||||||
|
url: http://influxdb:8086
|
||||||
|
isDefault: true
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
import http from 'k6/http';
|
||||||
|
import { sleep } from 'k6';
|
||||||
|
|
||||||
|
export let options = {
|
||||||
|
scenarios: {
|
||||||
|
normal: {
|
||||||
|
executor: 'constant-vus',
|
||||||
|
vus: 200,
|
||||||
|
duration: '10s',
|
||||||
|
exec: "normal",
|
||||||
|
gracefulStop: '0s',
|
||||||
|
},
|
||||||
|
notFound: {
|
||||||
|
executor: 'constant-vus',
|
||||||
|
vus: 200,
|
||||||
|
duration: '10s',
|
||||||
|
exec: "notFound",
|
||||||
|
gracefulStop: '0s',
|
||||||
|
startTime: '10s'
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
executor: 'constant-vus',
|
||||||
|
vus: 200,
|
||||||
|
duration: '10s',
|
||||||
|
exec: "error",
|
||||||
|
gracefulStop: '0s',
|
||||||
|
startTime: '20s'
|
||||||
|
},
|
||||||
|
slow: {
|
||||||
|
executor: 'constant-vus',
|
||||||
|
vus: 200,
|
||||||
|
duration: '10s',
|
||||||
|
exec: "slow",
|
||||||
|
gracefulStop: '10s',
|
||||||
|
startTime: '30s'
|
||||||
|
},
|
||||||
|
verySlow: {
|
||||||
|
executor: 'constant-vus',
|
||||||
|
vus: 200,
|
||||||
|
duration: '10s',
|
||||||
|
exec: "verySlow",
|
||||||
|
gracefulStop: '30s',
|
||||||
|
startTime: '50s'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const host = "http://host.docker.internal:5000";
|
||||||
|
|
||||||
|
export function normal() {
|
||||||
|
http.get(host + "/product/1/similar");
|
||||||
|
sleep(0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function slow() {
|
||||||
|
http.get(host + "/product/2/similar");
|
||||||
|
sleep(0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function verySlow() {
|
||||||
|
http.get(host + "/product/3/similar");
|
||||||
|
sleep(0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function notFound() {
|
||||||
|
http.get(host + "/product/4/similar");
|
||||||
|
sleep(0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function error() {
|
||||||
|
http.get(host + "/product/5/similar");
|
||||||
|
sleep(0.5);
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"path": "/product/1/similarids",
|
||||||
|
"body": "[2,3,4]",
|
||||||
|
"headers": {"Content-Type": "application/json"}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/product/2/similarids",
|
||||||
|
"body": "[3,100,1000]",
|
||||||
|
"headers": {"Content-Type": "application/json"}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/product/3/similarids",
|
||||||
|
"body": "[100,1000,10000]",
|
||||||
|
"headers": {"Content-Type": "application/json"}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/product/4/similarids",
|
||||||
|
"body": "[1,2,5]",
|
||||||
|
"headers": {"Content-Type": "application/json"}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/product/5/similarids",
|
||||||
|
"body": "[1,2,6]",
|
||||||
|
"headers": {"Content-Type": "application/json"}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/product/1",
|
||||||
|
"body": "{\"id\":\"1\",\"name\":\"Shirt\",\"price\":9.99,\"availability\":true}",
|
||||||
|
"headers": {"Content-Type": "application/json"}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/product/2",
|
||||||
|
"body": "{\"id\":\"2\",\"name\":\"Dress\",\"price\":19.99,\"availability\":true}",
|
||||||
|
"headers": {"Content-Type": "application/json"}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/product/3",
|
||||||
|
"body": "{\"id\":\"3\",\"name\":\"Blazer\",\"price\":29.99,\"availability\":false}",
|
||||||
|
"headers": {"Content-Type": "application/json"},
|
||||||
|
"delay": 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/product/4",
|
||||||
|
"body": "{\"id\":\"4\",\"name\":\"Boots\",\"price\":39.99,\"availability\":true}",
|
||||||
|
"headers": {"Content-Type": "application/json"}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/product/5",
|
||||||
|
"body": "{\"message\":\"Product not found\"}",
|
||||||
|
"status": 404,
|
||||||
|
"headers": {"Content-Type": "application/json"}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/product/6",
|
||||||
|
"status": 500,
|
||||||
|
"headers": {"Content-Type": "application/json"}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/product/100",
|
||||||
|
"body": "{\"id\":\"100\",\"name\":\"Trousers\",\"price\":49.99,\"availability\":false}",
|
||||||
|
"delay": 1000,
|
||||||
|
"headers": {"Content-Type": "application/json"}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/product/1000",
|
||||||
|
"body": "{\"id\":\"1000\",\"name\":\"Coat\",\"price\":89.99,\"availability\":true}",
|
||||||
|
"delay": 5000,
|
||||||
|
"headers": {"Content-Type": "application/json"}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/product/10000",
|
||||||
|
"body": "{\"id\":\"10000\",\"name\":\"Leather jacket\",\"price\":89.99,\"availability\":true}",
|
||||||
|
"delay": 50000,
|
||||||
|
"headers": {"Content-Type": "application/json"}
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
openapi: 3.0.0
|
||||||
|
info:
|
||||||
|
title: SimilarProducts
|
||||||
|
version: '1.0'
|
||||||
|
servers:
|
||||||
|
- url: 'http://localhost:5000'
|
||||||
|
paths:
|
||||||
|
'/product/{productId}/similar':
|
||||||
|
parameters:
|
||||||
|
- schema:
|
||||||
|
type: string
|
||||||
|
name: productId
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
get:
|
||||||
|
operationId: get-product-similar
|
||||||
|
summary: Similar products
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: OK
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
description: 'List of similar products to a given one ordered by similarity'
|
||||||
|
minItems: 0
|
||||||
|
uniqueItems: true
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- name
|
||||||
|
- price
|
||||||
|
- availability
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
minLength: 1
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
minLength: 1
|
||||||
|
price:
|
||||||
|
type: number
|
||||||
|
availability:
|
||||||
|
type: boolean
|
||||||
Reference in New Issue
Block a user