From 27b3773c79bc85f3c2b50c78c32034758a292982 Mon Sep 17 00:00:00 2001 From: Suphonchai Phoonsawat Date: Tue, 20 Jan 2026 20:54:47 +0700 Subject: [PATCH 1/2] load test script --- dotnet_leave_test.js | 54 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 dotnet_leave_test.js diff --git a/dotnet_leave_test.js b/dotnet_leave_test.js new file mode 100644 index 00000000..5add397d --- /dev/null +++ b/dotnet_leave_test.js @@ -0,0 +1,54 @@ +// ทดสอบการยิง 30,000 requests ในเวลา 10 นาที โดยให้กระจายการยิงในเวลาที่ต่างๆ กัน + +import { check, sleep } from "k6"; +import http from "k6/http"; +import { Rate } from "k6/metrics"; + +export let errorRate = new Rate("errors"); + +// จำนวน request ที่ต้องการยิง + +// ระยะเวลาทดสอบทั้งหมด + +// จำนวน Virtual Users เฉลี่ยที่ต้องการ 300 users +//const averageVus = Math.ceil(totalRequests / totalDuration); +const averageVus = 300; + +export let options = { + stages: [ + { duration: "2m", target: averageVus * 0.5 }, // 20% ของการทดสอบ เพิ่ม VUs เป็น 50% ของค่าเฉลี่ย + { duration: "4m", target: averageVus }, // 40% ของการทดสอบ เพิ่ม VUs เป็น 100% ของค่าเฉลี่ย + { duration: "2m", target: averageVus * 1.5 }, // 20% ของการทดสอบ เพิ่ม VUs เป็น 150% ของค่าเฉลี่ย + { duration: "2m", target: 0 }, // ลด VUs ลงมาเป็น 0 + ], + thresholds: { + errors: ["rate<0.01"], // อัตรา error ต้องน้อยกว่า 1% + http_req_duration: ["p(95)<2000"], // 95% ของ requests ควรใช้เวลาไม่เกิน 2 วินาที + }, +}; + +export default function () { + // ตัวเลือก headers + let headers = { + "Content-Type": "application/json", + Authorization: + "Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ4WTJWUi1FRnZ2TlBzTXMzOXU4b29WQldRTDZtUHdyTkpPaDNrb0pGVGdVIn0.eyJleHAiOjE3NzYyMTkxNjgsImlhdCI6MTc2ODQ0MzE2OCwianRpIjoiZDQxMmI5MWEtZmZhMi00N2JiLTliZDUtZDE5NTdmMDFjYzQyIiwiaXNzIjoiaHR0cHM6Ly9ocm1zLWlkLmJhbmdrb2suZ28udGgvcmVhbG1zL2hybXMiLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiYmFmYzU3OTUtYmVmYy00ZDNmLWE0NjEtMzUzM2MzOGE1ZmMxIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoiZ2V0dG9rZW4tY2hlY2tpbiIsInNpZCI6IjBkNzdiY2Y5LTE4YWQtNGQyMS1hYjBjLTI4Y2ZiZjUyZGZiNCIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiaHR0cHM6Ly9ocm1zLmJhbmdrb2suZ28udGgiLCJodHRwczovL2hybXMtY2hlY2tpbi5iYW5na29rLmdvLnRoIl0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJTVVBFUl9BRE1JTiIsInN0b3JhZ2VfbWFuYWdlbWVudCIsIm9mZmxpbmVfYWNjZXNzIiwiU1RBRkYiLCJkZWZhdWx0LXJvbGVzLWhybXMiLCJ1bWFfYXV0aG9yaXphdGlvbiIsIkFETUlOIiwiVVNFUiJdfSwicmVzb3VyY2VfYWNjZXNzIjp7ImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyIsInZpZXctcHJvZmlsZSJdfX0sInNjb3BlIjoiZW1haWwgb3BlbmlkIHByb2ZpbGUiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInJvbGUiOlsiU1VQRVJfQURNSU4iLCJzdG9yYWdlX21hbmFnZW1lbnQiLCJvZmZsaW5lX2FjY2VzcyIsIlNUQUZGIiwiZGVmYXVsdC1yb2xlcy1ocm1zIiwidW1hX2F1dGhvcml6YXRpb24iLCJBRE1JTiIsIlVTRVIiXSwibmFtZSI6IuC4p-C4seC4meC5gOC4ieC4peC4tOC4oSDguInguLHguJXguKPguJfguK3guIciLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiIzMTIwMjAwNDI0OTc1IiwiZ2l2ZW5fbmFtZSI6IuC4p-C4seC4meC5gOC4ieC4peC4tOC4oSIsImZhbWlseV9uYW1lIjoi4LiJ4Lix4LiV4Lij4LiX4Lit4LiHIn0.UhMn0NEkymPxMAcb4noZedHCSqXotCyD2RziBtLYHn5OhA9yk1915Rrt9iV4wVaebr74iZ2eZMpBwp8YVy8-3cPXSv9T3vzbXwFP7IeICPCDDf4bOPFEHP5FYow2s9v48qG81wnu01AG7_EL2-CQKh1sBVrCVUUlATlf-P4lT_lHeHOCKNXTmw4V0IWm96ec6pk-jFY3KH2JdRSWR7wq8g-KVxhLOxk_pF72kMwOpdvcr_99byg28zzj6QfeNYXLt61koHXnZppUqytt86mQQgfamv2FNVywCEzbRITUceu2rmJnwQE8ubeoCh4UOsYauUuSKd7RPqvvXxL_Vg__8Q", + //"Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJTT2wwWmFidm9rRzZET3pDZVBtT09Kek5haTdMUldkci1zV3lEYjRELTc0In0.eyJleHAiOjE3Njg4ODAzMjgsImlhdCI6MTc2ODc5MzkyOCwianRpIjoiMDYxODBlMWYtNTQzYy00MjU0LWFmN2QtYWI1NDA5NzFmNWY2IiwiaXNzIjoiaHR0cHM6Ly9ocm1zYmtrLWlkLmNhc2UtY29sbGVjdGlvbi5jb20vcmVhbG1zL2hybXMiLCJhdWQiOlsiYWNjb3VudCIsImdldHRva2VuIl0sInN1YiI6IjQzOWZhMzZkLTZiYzUtNGVmNS05NWFhLWVmMjllNjRkMmU5ZiIsInR5cCI6IkJlYXJlciIsImF6cCI6ImdldHRva2VuIiwic2lkIjoiZGI2YzUxNjItNzZhYS00MmVmLWI0ZDMtYThmOTk2N2NjZWM2IiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIqIl0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJTVVBFUl9BRE1JTiIsIm9mZmxpbmVfYWNjZXNzIiwiU1RBRkYiLCJkZWZhdWx0LXJvbGVzLWhybXMiLCJ1bWFfYXV0aG9yaXphdGlvbiIsIkFETUlOIiwiVVNFUiJdfSwicmVzb3VyY2VfYWNjZXNzIjp7ImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyIsInZpZXctcHJvZmlsZSJdfX0sInNjb3BlIjoiZW1haWwgb3BlbmlkIHByb2ZpbGUiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInJvbGUiOlsiU1VQRVJfQURNSU4iLCJvZmZsaW5lX2FjY2VzcyIsIlNUQUZGIiwiZGVmYXVsdC1yb2xlcy1ocm1zIiwidW1hX2F1dGhvcml6YXRpb24iLCJBRE1JTiIsIlVTRVIiXSwibmFtZSI6IuC4p-C4seC4meC5gOC4ieC4peC4tOC4oSDguInguLHguJXguKPguJfguK3guIciLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiIzMTIwMjAwNDI0OTc1IiwiZ2l2ZW5fbmFtZSI6IuC4p-C4seC4meC5gOC4ieC4peC4tOC4oSIsImZhbWlseV9uYW1lIjoi4LiJ4Lix4LiV4Lij4LiX4Lit4LiHIn0.fHdMzpHMD4JcbzYnUrfM473FSXka2Z4lz_S3HI2c-dPXfO5ATpijqsi12C6-ExE0RJRXUK671erMuyVXL6u2qj-FvdliBL3ubKy4J3jIT3svkcZxZL2ib16dRg375dITefvqd-J4vw6MR4bq8YAGPbqRIy6BQ2pdEiZgNiwUUihHAFwZlVER1lNbaqlbL6vk_L4k-g25DBVnDr756BFvrw7zEDbawkKZ31EZF5_DYk4RWej0wvWrGHQWLw-RyzYVSBB_AooqHkncHn_CwLBGC5juOEfFO4a2ThuKwoxYCstjtBj-zmjpHFs-Hh3CBTWJCGFcKst1Ey28StlKtNkLiw", + }; + + // ส่ง GET request + let response = http.get( + //"https://bma-hrms.bangkok.go.th/api/v1/leave/fake-check-in", + //"https://hrmsbkk.case-collection.com/api/v1/org/dotnet/keycloak/439fa36d-6bc5-4ef5-95aa-ef29e64d2e9f", + "https://hrms.bangkok.go.th/api/v1/leave/check-time", + { headers: headers }, + ); + + // ตรวจสอบการตอบสนอง + check(response, { + "is status 200": (r) => r.status === 200, + }); + + // หน่วงเวลา 1 วินาที + sleep(1); +} From d3501e831c4e8ebe4fd20c42af50cea2b78830f5 Mon Sep 17 00:00:00 2001 From: harid Date: Wed, 21 Jan 2026 17:00:45 +0700 Subject: [PATCH 2/2] =?UTF-8?q?fix=20=E0=B8=81=E0=B8=88.=20=E0=B9=84?= =?UTF-8?q?=E0=B8=A1=E0=B9=88=E0=B9=80=E0=B8=AB=E0=B9=87=E0=B8=99=E0=B8=A3?= =?UTF-8?q?=E0=B8=B2=E0=B8=A2=E0=B8=8A=E0=B8=B7=E0=B9=88=E0=B8=AD=E0=B8=9C?= =?UTF-8?q?=E0=B8=B9=E0=B9=89=E0=B8=AA=E0=B8=AD=E0=B8=9A=E0=B8=9C=E0=B9=88?= =?UTF-8?q?=E0=B8=B2=E0=B8=99=E0=B8=AB=E0=B8=A5=E0=B8=B1=E0=B8=87=E0=B8=88?= =?UTF-8?q?=E0=B8=B2=E0=B8=81=E0=B9=80=E0=B8=9C=E0=B8=A2=E0=B9=81=E0=B8=9E?= =?UTF-8?q?=E0=B8=A3=E0=B9=88=E0=B9=82=E0=B8=84=E0=B8=A3=E0=B8=87=E0=B8=AA?= =?UTF-8?q?=E0=B8=A3=E0=B9=89=E0=B8=B2=E0=B8=87=20Task=20#2219?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/PlacementController.cs | 18 +++++++++++------- .../Requests/OrgRequestAct.cs | 1 + 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/BMA.EHR.Placement.Service/Controllers/PlacementController.cs b/BMA.EHR.Placement.Service/Controllers/PlacementController.cs index 62b9bbce..a485a42d 100644 --- a/BMA.EHR.Placement.Service/Controllers/PlacementController.cs +++ b/BMA.EHR.Placement.Service/Controllers/PlacementController.cs @@ -155,6 +155,7 @@ namespace BMA.EHR.Placement.Service.Controllers var child2Id = ""; var child3Id = ""; var child4Id = ""; + var rootDnaId = ""; var apiUrl = $"{_configuration["API"]}/org/profile/keycloak/position-act"; using (var client = new HttpClient()) { @@ -173,11 +174,12 @@ namespace BMA.EHR.Placement.Service.Controllers // child2Id = org.result.child2Id == null ? "" : org.result.child2Id; // child3Id = org.result.child3Id == null ? "" : org.result.child3Id; // child4Id = org.result.child4Id == null ? "" : org.result.child4Id; + rootDnaId = org.result.rootDnaId == null ? "" : org.result.rootDnaId; var data1 = await _context.PlacementProfiles .Where(x => x.Placement.Id == examId) .Where(x => x.Draft == true) .Where(x => x.PlacementStatus != "UN-CONTAIN") - .Where(x => rootId == "" ? true : (child1Id == "" ? x.rootId == rootId : (child2Id == "" ? x.child1Id == child1Id : (child3Id == "" ? x.child2Id == child2Id : (child4Id == "" ? x.child3Id == child3Id : x.child4Id == child4Id))))) + .Where(x => rootDnaId == "" ? true : (child1Id == "" ? x.rootDnaId == rootDnaId : (child2Id == "" ? x.child1Id == child1Id : (child3Id == "" ? x.child2Id == child2Id : (child4Id == "" ? x.child3Id == child3Id : x.child4Id == child4Id))))) .Select(x => new { Id = x.Id, @@ -694,6 +696,7 @@ namespace BMA.EHR.Placement.Service.Controllers var child2Id = ""; var child3Id = ""; var child4Id = ""; + var rootDnaId = ""; var apiUrl = $"{_configuration["API"]}/org/profile/keycloak/position-act"; using (var client = new HttpClient()) { @@ -713,16 +716,17 @@ namespace BMA.EHR.Placement.Service.Controllers // child2Id = org.result.child2Id == null ? "" : org.result.child2Id; // child3Id = org.result.child3Id == null ? "" : org.result.child3Id; // child4Id = org.result.child4Id == null ? "" : org.result.child4Id; + rootDnaId = org.result.rootDnaId == null ? "" : org.result.rootDnaId; var placement = await _context.Placements .Where(x => x.Id == examId) .Select(x => new { - Total = x.PlacementProfiles.Where(x => x.Draft == true).Where(x => rootId == "" ? true : (child1Id == "" ? x.rootId == rootId : (child2Id == "" ? x.child1Id == child1Id : (child3Id == "" ? x.child2Id == child2Id : (child4Id == "" ? x.child3Id == child3Id : x.child4Id == child4Id))))).Count(), - UnContain = x.PlacementProfiles.Where(x => x.Draft == true).Where(x => rootId == "" ? true : (child1Id == "" ? x.rootId == rootId : (child2Id == "" ? x.child1Id == child1Id : (child3Id == "" ? x.child2Id == child2Id : (child4Id == "" ? x.child3Id == child3Id : x.child4Id == child4Id))))).Where(p => p.PlacementStatus.Trim().ToUpper() == "UN-CONTAIN").Count(), - PrepareContain = x.PlacementProfiles.Where(x => x.Draft == true).Where(x => rootId == "" ? true : (child1Id == "" ? x.rootId == rootId : (child2Id == "" ? x.child1Id == child1Id : (child3Id == "" ? x.child2Id == child2Id : (child4Id == "" ? x.child3Id == child3Id : x.child4Id == child4Id))))).Where(p => p.PlacementStatus.Trim().ToUpper() == "PREPARE-CONTAIN").Count(), - Report = x.PlacementProfiles.Where(x => x.Draft == true).Where(x => rootId == "" ? true : (child1Id == "" ? x.rootId == rootId : (child2Id == "" ? x.child1Id == child1Id : (child3Id == "" ? x.child2Id == child2Id : (child4Id == "" ? x.child3Id == child3Id : x.child4Id == child4Id))))).Where(p => p.PlacementStatus.Trim().ToUpper() == "REPORT").Count(), - Done = x.PlacementProfiles.Where(x => x.Draft == true).Where(x => rootId == "" ? true : (child1Id == "" ? x.rootId == rootId : (child2Id == "" ? x.child1Id == child1Id : (child3Id == "" ? x.child2Id == child2Id : (child4Id == "" ? x.child3Id == child3Id : x.child4Id == child4Id))))).Where(p => p.PlacementStatus.Trim().ToUpper() == "DONE").Count(), - Disclaim = x.PlacementProfiles.Where(x => x.Draft == true).Where(x => rootId == "" ? true : (child1Id == "" ? x.rootId == rootId : (child2Id == "" ? x.child1Id == child1Id : (child3Id == "" ? x.child2Id == child2Id : (child4Id == "" ? x.child3Id == child3Id : x.child4Id == child4Id))))).Where(p => p.PlacementStatus.Trim().ToUpper() == "DISCLAIM").Count(), + Total = x.PlacementProfiles.Where(x => x.Draft == true).Where(x => rootDnaId == "" ? true : (child1Id == "" ? x.rootDnaId == rootDnaId : (child2Id == "" ? x.child1Id == child1Id : (child3Id == "" ? x.child2Id == child2Id : (child4Id == "" ? x.child3Id == child3Id : x.child4Id == child4Id))))).Count(), + UnContain = x.PlacementProfiles.Where(x => x.Draft == true).Where(x => rootDnaId == "" ? true : (child1Id == "" ? x.rootDnaId == rootDnaId : (child2Id == "" ? x.child1Id == child1Id : (child3Id == "" ? x.child2Id == child2Id : (child4Id == "" ? x.child3Id == child3Id : x.child4Id == child4Id))))).Where(p => p.PlacementStatus.Trim().ToUpper() == "UN-CONTAIN").Count(), + PrepareContain = x.PlacementProfiles.Where(x => x.Draft == true).Where(x => rootDnaId == "" ? true : (child1Id == "" ? x.rootDnaId == rootDnaId : (child2Id == "" ? x.child1Id == child1Id : (child3Id == "" ? x.child2Id == child2Id : (child4Id == "" ? x.child3Id == child3Id : x.child4Id == child4Id))))).Where(p => p.PlacementStatus.Trim().ToUpper() == "PREPARE-CONTAIN").Count(), + Report = x.PlacementProfiles.Where(x => x.Draft == true).Where(x => rootDnaId == "" ? true : (child1Id == "" ? x.rootDnaId == rootDnaId : (child2Id == "" ? x.child1Id == child1Id : (child3Id == "" ? x.child2Id == child2Id : (child4Id == "" ? x.child3Id == child3Id : x.child4Id == child4Id))))).Where(p => p.PlacementStatus.Trim().ToUpper() == "REPORT").Count(), + Done = x.PlacementProfiles.Where(x => x.Draft == true).Where(x => rootDnaId == "" ? true : (child1Id == "" ? x.rootDnaId == rootDnaId : (child2Id == "" ? x.child1Id == child1Id : (child3Id == "" ? x.child2Id == child2Id : (child4Id == "" ? x.child3Id == child3Id : x.child4Id == child4Id))))).Where(p => p.PlacementStatus.Trim().ToUpper() == "DONE").Count(), + Disclaim = x.PlacementProfiles.Where(x => x.Draft == true).Where(x => rootDnaId == "" ? true : (child1Id == "" ? x.rootDnaId == rootDnaId : (child2Id == "" ? x.child1Id == child1Id : (child3Id == "" ? x.child2Id == child2Id : (child4Id == "" ? x.child3Id == child3Id : x.child4Id == child4Id))))).Where(p => p.PlacementStatus.Trim().ToUpper() == "DISCLAIM").Count(), }).FirstOrDefaultAsync(); if (placement == null) return Error(GlobalMessages.DataNotFound, 404); diff --git a/BMA.EHR.Placement.Service/Requests/OrgRequestAct.cs b/BMA.EHR.Placement.Service/Requests/OrgRequestAct.cs index dace91d3..6189eaf4 100644 --- a/BMA.EHR.Placement.Service/Requests/OrgRequestAct.cs +++ b/BMA.EHR.Placement.Service/Requests/OrgRequestAct.cs @@ -15,5 +15,6 @@ namespace BMA.EHR.Placement.Service.Requests public string? child2Id { get; set; } public string? child3Id { get; set; } public string? child4Id { get; set; } + public string? rootDnaId { get; set; } } } \ No newline at end of file