วิธีทำไฟล์เสียหายสำหรับการทดสอบ
ตัวตรวจสอบที่เคยเห็นแต่ไฟล์ปกติยังไม่ถือว่าผ่านการทดสอบจริง นี่คือวิธีได้ไฟล์ที่ตั้งใจทำให้เสีย ออกมาขนาดตรงตามที่ขอเป๊ะ และมาพร้อมแมนิเฟสต์ที่บอกว่าระบบของคุณควรทำอะไรกับไฟล์นั้น
คำตอบสั้นๆ
tfg generate --format png --size 2mb --damage zero-head --out ./out เขียน PNG ขนาด
2097152 ไบต์พอดี โดยไบต์แรกๆ เป็นศูนย์ และแมนิเฟสต์ที่อยู่ข้างๆ
บันทึกว่าระบบของคุณควรปฏิเสธไฟล์นี้
วิธีที่ทำกันทั่วไป
ทำไมไฟล์ที่ทำให้เสียด้วยมือจึงเป็นการทดสอบที่แย่
วิธีทั่วไปคือใช้โปรแกรมแก้ไขเลขฐานสิบหก สคริปต์ที่สลับไบต์สุ่มไม่กี่ตัว หรือตัดไฟล์ให้สั้นลงด้วย
head หรือ truncate ใช้ได้ครั้งเดียว แล้วจะเสียเวลาในภายหลัง:
- ได้ผลต่างกันทุกครั้ง ไบต์สุ่มตกที่ใหม่ทุกครั้งที่รัน ความล้มเหลวของวันอังคารจึงอาจไม่กลับมาในวันพุธ
- มันเปลี่ยนขนาด ไฟล์ที่ถูกตัดจะเล็กกว่าขีดจำกัดที่มันควรอยู่ต่ำกว่า การตรวจขนาดจึงตอบก่อนการตรวจเนื้อหา และการทดสอบผ่านด้วยเหตุผลที่ผิด
- มักไม่มีใครสังเกต ข้อความธรรมดายังอ่านได้แม้เปลี่ยนไบต์กลางไฟล์ และตัวอ่านภาพที่ใจกว้างก็แค่วาดมันออกมา ไฟล์ที่ควรจะเสียจึงถูกรับไป
- มันไม่บอกว่าควรเกิดอะไรขึ้น ไฟล์เป็นแค่ไบต์ และคนที่มาอ่านการทดสอบทีหลังต้องเดาเองว่าตั้งใจให้รับหรือปฏิเสธ
สิ่งที่คุณได้
ไฟล์ที่เสียหายยังมีขนาดตามที่คุณขอ
ไฟล์ถูกสร้างตามปกติแล้วค่อยทำให้เสียระหว่างทางไปยังดิสก์ ขนาดยังเป็นไปตามที่ขอ และคำสั่งเดิมเขียนไบต์เดิมซ้ำอีกครั้ง
tfg generate --format png --size 2mb --damage zero-head --out ./out
tfg generate --format pdf --size 1mb --count 5 --damage zero-head:bytes=16 --out ./broken
การตั้งค่าเขียนหลังเครื่องหมายทวิภาค ตัวเลือกนี้ใส่ซ้ำได้ และความเสียหายจะถูกนำมาใช้ตามลำดับที่คุณเขียน ใช้ได้กับทั้ง 26 รูปแบบ
มันทำอะไรได้
มีความเสียหายแบบไหนบ้าง
นี่คือรายการที่โปรแกรมพิมพ์ออกมา อ่านจากตัวโปรแกรมเองตอนสร้างหน้านี้ tfg damage
พิมพ์รายการเดียวกัน และ tfg damage <id> บอกว่าแบบหนึ่งรับอะไรบ้าง
| ความเสียหาย | สิ่งที่ทำกับไบต์ | ไฟล์เล็กที่สุด | การตั้งค่า |
|---|---|---|---|
zero-head |
เขียนทับไบต์แรกๆ ของไฟล์ด้วยศูนย์ โดยไม่แตะความยาว ตัวอ่านส่วนใหญ่มองตรงนั้นก่อน เกือบทุกอย่างจึงสังเกตเห็นความเสียหายนี้ | 8 | bytes |
zero-head เขียนศูนย์ทับส่วนต้นของไฟล์ ตัวอ่านส่วนใหญ่มองตรงนั้นก่อน
คือลายเซ็นและส่วนหัวที่บอกว่าไฟล์คืออะไร ตัวอ่านเกือบทุกตัวจึงสังเกตเห็น
ข้อความธรรมดาและล็อกไม่มีลายเซ็นและก็ถูกปฏิเสธเช่นกัน เพราะไบต์ศูนย์ต่อกันไม่ใช่ข้อความ
ต่ำกว่าสี่ไบต์ บางรูปแบบออกมาพร้อมความเสียหายที่ไม่มีตัวอ่านใดบ่น
นั่นคือเหตุผลที่การตั้งค่าเริ่มที่สี่
แมนิเฟสต์บอกอะไร
แมนิเฟสต์ที่บอกว่าควรเกิดอะไรขึ้น
ไฟล์ที่เสียหายทุกไฟล์ได้รายการที่บอกว่าระบบของคุณควรปฏิเสธ โดยบันทึกความเสียหายไว้ข้างๆ:
"expected": {
"outcome": "reject",
"reason": "content_malformed",
"confidence": "certain"
},
"damage": [
{
"type": "zero-head",
"settings": {
"bytes": "8"
}
}
]
คำขอสองแบบถูกปฏิเสธก่อนที่จะมีอะไรถูกเขียน เพราะแต่ละแบบจะทิ้งไฟล์ไว้บนดิสก์ที่แมนิเฟสต์อธิบายผิด:
- ไฟล์ที่เล็กกว่าที่ความเสียหายต้องการ ซึ่งจะออกมาโดยไม่เปลี่ยนแปลง
-
expected: acceptคู่กับความเสียหาย เพราะไม่มีอะไรทำให้เป็นจริงได้ เขียนsanitizeถ้าระบบของคุณควรซ่อมไฟล์ หรือunspecifiedถ้านั่นคือคำถามที่คุณกำลังถาม
ในสูตร
ไฟล์ปกติและไฟล์เสียในการรันเดียว
ใส่ทั้งสองอย่างในสูตรเดียว แล้วแมนิเฟสต์จะมีสิ่งที่คาดหวังของแต่ละไฟล์ การทดสอบจึงไม่ต้องมีรายการบอกว่าไฟล์ไหนเป็นไฟล์ไหน:
version: 1
targets:
- id: healthy
format: pdf
size: 1mb
expected: accept
- id: broken
format: pdf
size: 1mb
damage:
- zero-head
ในการทดสอบ
เปลี่ยนให้เป็นการทดสอบ
การทดสอบอ่านแมนิเฟสต์แล้วตรวจว่าสิ่งที่เกิดขึ้นตรงกับที่ประกาศไว้ ไม่ต้องมีรายชื่อไฟล์:
import json, os
directory = "healthy-and-broken"
manifest = json.load(open(os.path.join(directory, "manifest.json")))
for entry in manifest["files"]:
response = upload(os.path.join(directory, entry["path"]))
if entry["expected"]["outcome"] == "reject":
assert not response.ok
else:
assert response.ok
การปฏิเสธที่ดีคือการปฏิเสธที่สะอาด ข้อความที่บอกว่าผิดตรงไหนคือคำตอบที่คุณต้องการ ส่วนข้อผิดพลาดของเซิร์ฟเวอร์ การค้าง หรือไฟล์ที่บันทึกไว้ครึ่งเดียวคือข้อบกพร่องที่การทดสอบนี้มีไว้หา
ถัดไป
จากตรงนี้ไปไหนต่อ
- พรีเซ็ต upload-validation ถามฟอร์มสองคำถามที่เหลือ คือเรื่องขนาดและเรื่องชนิด
- ไฟล์ทดสอบใน CI รันสูตรแบบนี้ในไปป์ไลน์
-
เอกสาร มีทุกตัวเลือกของ
tfg generate