diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml new file mode 100644 index 0000000..67e170c --- /dev/null +++ b/.github/workflows/performance.yml @@ -0,0 +1,13 @@ +name: Main Workflow +on: [push] +jobs: + build: + name: Run k6 test + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Run k6 local test + uses: grafana/k6-action@v0.3.1 + with: + filename: tests/performance/tests/perf.js \ No newline at end of file diff --git a/.gitignore b/.gitignore index d48c759..3a86eaa 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .idea -.vscode \ No newline at end of file +.vscode +/tests/performance/node_modules \ No newline at end of file diff --git a/tests/expense_test.go b/tests/integration/expense_test.go similarity index 100% rename from tests/expense_test.go rename to tests/integration/expense_test.go diff --git a/tests/payments_test.go b/tests/integration/payments_test.go similarity index 97% rename from tests/payments_test.go rename to tests/integration/payments_test.go index a408e75..5f49f24 100644 --- a/tests/payments_test.go +++ b/tests/integration/payments_test.go @@ -28,7 +28,7 @@ func TestPaymentsAPI(t *testing.T) { Currency: "AUD", Timestamp: time.Now().UnixNano() / int64(time.Millisecond), PaymentMethod: "credit", - Status: "success", + Status: "COMPLETED", }, expected: http.StatusOK, }, diff --git a/tests/performance/package-lock.json b/tests/performance/package-lock.json new file mode 100644 index 0000000..e144dc5 --- /dev/null +++ b/tests/performance/package-lock.json @@ -0,0 +1,22 @@ +{ + "name": "performance", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "performance", + "version": "1.0.0", + "license": "MIT", + "devDependencies": { + "@types/k6": "^0.50.0" + } + }, + "node_modules/@types/k6": { + "version": "0.50.0", + "resolved": "https://registry.npmjs.org/@types/k6/-/k6-0.50.0.tgz", + "integrity": "sha512-+KpsLr549oFSpr80Zk9lf9wsEgESYTYzGeBIlS6NnH4PBiqJuRk+xv3KSFfDOCD0ZHbhUsXMV7mEVhWLOzfzmw==", + "dev": true + } + } +} diff --git a/tests/performance/package.json b/tests/performance/package.json new file mode 100644 index 0000000..7acbb2a --- /dev/null +++ b/tests/performance/package.json @@ -0,0 +1,14 @@ +{ + "name": "performance", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "k6 run tests/perf.js" + }, + "author": "Dipjyoti Metia", + "license": "MIT", + "devDependencies": { + "@types/k6": "^0.50.0" + } +} diff --git a/tests/performance/tests/perf.js b/tests/performance/tests/perf.js new file mode 100644 index 0000000..43bc9fd --- /dev/null +++ b/tests/performance/tests/perf.js @@ -0,0 +1,91 @@ +import http from 'k6/http'; +import { check } from 'k6'; + +export const options = { + tags: { + test: 'api-performance', + test_run_id: `api-Load-Testing-${new Date().toISOString()}`, + }, + thresholds: { + 'http_req_failed{test_type:addExpense}': ['rate<0.01'], // http errors should be less than 1%, availability + 'http_req_duration{test_type:addExpense}': ['p(95)<200'], // 95% of requests should be below 200ms, latency + 'http_req_failed{test_type:addPayments}': ['rate<0.01'], // http errors should be less than 1%, availability + 'http_req_duration{test_type:addPayments}': ['p(95)<200'], // 95% of requests should be below 200ms, latency + }, + scenarios: { + // Load testing using K6 constant-rate scenario + addExpense_constant: { + executor: 'constant-arrival-rate', + rate: 10000, // number of iterations per time unit + timeUnit: '1m', // iterations will be per minute + duration: '1m', // total duration that the test will run for + preAllocatedVUs: 2, // the size of the VU (i.e. worker) pool for this scenario + maxVUs: 25, // if the preAllocatedVUs are not enough, we can initialize more + tags: { test_type: 'addExpense' }, // different extra metric tags for this scenario + exec: 'addExpense',// Test scenario function to call + }, + addPayments_constant: { + executor: 'constant-arrival-rate', + rate: 10000, // number of iterations per time unit + timeUnit: '1m', // iterations will be per minute + duration: '1m', // total duration that the test will run for + preAllocatedVUs: 2, // the size of the VU (i.e. worker) pool for this scenario + maxVUs: 25, // if the preAllocatedVUs are not enough, we can initialize more + tags: { test_type: 'addPayments' }, // different extra metric tags for this scenario + exec: 'addPayments',// Test scenario function to call + } + } +}; + +export function addExpense() { + const url = 'http://localhost:8083/api/expense'; + + const payload = JSON.stringify({ + expense_id: 'test', + user_id: '10010', + category: 'kafkaSync', + amount: 12.5, + currency: 'AUD', + timestamp: Date.now(), + description: 'Any', + receipt: 'newTest', + }); + + const params = { + headers: { + 'Content-Type': 'application/json', + }, + }; + + const response = http.post(url, payload, params); + + check(response, { + 'is status 200': (r) => r.status === 200, + }); +} + +export function addPayments() { + const url = 'http://localhost:8083/api/payment'; + + const payload = JSON.stringify({ + transaction_id: 'test', + user_id: '10010', + amount: 12.5, + currency: 'AUD', + payment_method:'CREDIT_CARD', + timestamp: Date.now(), + status: 'COMPLETED', + }); + + const params = { + headers: { + 'Content-Type': 'application/json', + }, + }; + + const response = http.post(url, payload, params); + + check(response, { + 'is status 200': (r) => r.status === 200, + }); +} \ No newline at end of file