Private Docs

ทดสอบว่าใช้งานได้จริง — แม่แบบ 4 เคส + กับดักตอนรันในเครื่อง

ชุดทดสอบที่ใช้พิสูจน์จริงกับ service ตัวแรก คัดลอกไปใช้ได้เลย · รวมกับดักที่ทำให้ 'ทดสอบผ่าน' ทั้งที่ระบบป้องกันปิดอยู่ และรายการอุบัติเหตุตอนรันในเครื่องที่เสียเวลาซ้ำ ๆ

อัปเดต: 2026-08-23

ทุกบรรทัดในหน้านี้มาจากการรันจริงกับ service ตัวแรกที่ทำเสร็จ ไม่ใช่แบบฝึกหัดที่แต่งขึ้น

1. 🔴 กับดักใหญ่ที่สุด: ผลที่ดูเหมือนผ่าน ทั้งที่ระบบยังปิดอยู่

ตอนทดสอบจริงเจอเหตุการณ์นี้: ยิงคำขอ ที่ไม่ได้เซ็น แล้วได้ 200 — ซึ่ง “ดูเหมือนระบบทำงานปกติ”

ความจริงคือ สวิตช์ยังไม่เปิด ⇒ ทุกคำขอผ่านหมดไม่ว่าจะเซ็นหรือไม่เซ็น ถ้ารายงานตอนนั้นก็จะเป็นการรายงานว่า “ทดสอบผ่าน” ทั้งที่ยังไม่มีการป้องกันอะไรเลย

กฎที่ได้จากเหตุการณ์นี้:

เคสลบได้ 200  →  ไม่ใช่ "ผ่าน" แต่แปลว่า "การป้องกันปิดอยู่"  →  หยุด ไปเปิดสวิตช์ก่อน

และหลังเปลี่ยนค่าสวิตช์ ต้อง restart จริง (ค่าถูกอ่านครั้งเดียวตอน start) — พร้อมทั้ง ตรวจว่า process เก่าตายจริง ด้วยการ probe port ไม่ใช่เชื่อว่าสั่งหยุดแล้วมันหยุด

2. แม่แบบ 4 เคส (ทำตามลำดับนี้)

#เคสยิงยังไงต้องได้
0ลงทะเบียนกุญแจPOST {base}/v1/client-keys พร้อม token200 + สถานะ Registered
1เคสบวก — เซ็นถูกGET {base}/v1/client-keys/ping + X-Timestamp + X-Signature200
2เคสลบ — ไม่เซ็น แต่ token ถูกGET .../ping + token อย่างเดียว401 + SIG_MISSING_HEADER
3เส้นยกเว้นGET {base}/v1/security/jwks ไม่เซ็นต้องได้ error ทางธุรกิจหรือผลปกติ ไม่ใช่ 401 SIG_*
4เคสควบคุม — ไม่มี header อะไรเลยGET .../ping เปล่า ๆ401 แบบ หน้าตาต่างจากข้อ 2 อย่างชัดเจน

ทำไมต้องมีข้อ 4: มันพิสูจน์ว่าการเพิ่มชั้นลายเซ็น ไม่ได้ทำให้ชั้น authentication เดิมหลวมลง — ถ้าข้อ 2 กับข้อ 4 ให้ผลหน้าตาเหมือนกันเป๊ะ แปลว่าคุณอาจกำลังวัดชั้นเดียว ไม่ใช่สองชั้น

ทำไมเคสบวกต้องมาก่อน: ชุดทดสอบที่มีแต่เคสลบจะเขียวสนิทแม้ระบบจะปฏิเสธทุกคนโดยผิดพลาด (เจอมาแล้ว 2 service ในเรื่อง API key)

3. หลักฐานที่ต้องเก็บ

ต่อ 1 เคส: คำสั่งจริง + HTTP status + เนื้อหาที่ตอบกลับแบบย่อ + เวลา · ห้ามสรุปแทนตัวเลข ห้ามใช้ผลรันเก่า

curl -s -o /dev/null -w '%{http_code}\n' "$BASE/v1/client-keys/ping" -H "Authorization: Bearer $TOKEN"

รวมถึงเก็บ commit ที่ทดสอบ ไว้ด้วย:

git rev-parse HEAD    # ทดสอบบน commit ไหน ต้องบอกได้เสมอ

4. กับดักตอนรันในเครื่อง (แต่ละข้อมาจากอุบัติเหตุจริง)

กับดักอาการวิธีที่ถูก
dotnet user-secrets clearsecret ของทุก worktree หายพร้อมกัน (ใช้ไฟล์เดียวกัน) แล้ว boot ครั้งถัดไปพังแบบหาสาเหตุไม่เจอลบทีละ key ด้วย remove เท่านั้น
ตั้ง environment ด้วย argument--environment Development / --launch-profile ไม่ติด ⇒ ระบบคิดว่าเป็น Production ⇒ ไม่โหลด user-secrets ทั้งก้อนใช้ env var: ASPNETCORE_ENVIRONMENT=Development dotnet run
ค่าจาก KeyVault ทับ config ในเครื่องตั้ง Redis/ServiceBus ไว้ในเครื่องแล้วแต่แอปไปต่อของ cloudรู้ไว้ว่า env var จาก KeyVault ชนะทุกชั้น — ตรวจค่าจริงที่แอปเห็นตอน start
ลืมเคลียร์ connection string ของ ServiceBusboot ค้าง/ช้าเป็นนาทีเคลียร์ ทุกครั้ง ก่อน boot ไม่ใช่ครั้งเดียวจบ
กุญแจเข้ารหัสถูก generate ใหม่ทุกครั้งข้อมูลที่เข้ารหัสไว้รอบก่อนถอดไม่ได้ตั้งครั้งเดียวแล้วเก็บถาวรในเครื่อง
ลงทะเบียนกุญแจซ้ำได้ 409คิดว่าพังเป็นพฤติกรรมที่ถูก (กุญแจเดิมอายุ 7 วัน) ใช้ผู้ใช้ทดสอบคนใหม่หรือรอหมดอายุ
curl บน Git Bashpath /api/... ถูกแปลงเป็น path แบบ Windows เงียบ ๆ ⇒ ลายเซ็นเพี้ยนนำหน้าด้วย MSYS_NO_PATHCONV=1
สั่งหยุด process แล้วเชื่อว่าหยุดboot ใหม่ไปชนตัวเก่าที่ยังถือ port อยู่ แล้วทดสอบโค้ดเวอร์ชันเก่าprobe port จริงก่อน boot รอบใหม่เสมอ

5. ก่อนบอกว่า “เสร็จแล้ว”

dotnet build -c Release     # ต้อง 0 error (CI ใช้ Release และเปิด analyzer เป็น error)
dotnet test -c Release      # ต้อง 0 failed และต้องบอกจำนวนที่ผ่านได้
  • อย่ารันชุดทดสอบ 2 ชุดพร้อมกันแล้วเอาตัวเลขมารายงานปนกัน
  • ถ้าแก้ระบบป้องกันแล้วจำนวน test ที่ผ่าน ไม่เปลี่ยนเลย ให้สงสัยว่ายังไม่ได้ทดสอบสิ่งที่คิดว่าทดสอบ — ลองปิดโค้ดป้องกันดู test ต้องแดง ถ้ายังเขียวแปลว่าชุดทดสอบไม่ได้ตรวจของจริง
  • ทุกคำกล่าวว่า “ผ่าน” ต้องมาพร้อมผลรันจริง ไม่ใช่ “น่าจะผ่าน”