package storage import ( "encoding/json" "strings" "testing" ) // R-330 (disk health Phase 2) — attributes 187, 188 and 199 ride the wire. // // The failing drive of 2026-08-14 carried 187 Reported_Uncorrect at raw 1001 while SMART said PASSED; // none of the three reached the controller. The values are carried as RAW counters; an absent // attribute is OMITTED from the JSON (unknown), never sent as 0 (S-39). // The 2026-08-14 shape: PASSED, 187 raw 1001, plus 188/199 and the existing three. const r330SATA = `{"smart_status":{"passed":true},"ata_smart_attributes":{"table":[ {"id":5,"raw":{"value":0}}, {"id":187,"raw":{"value":1001}}, {"id":188,"raw":{"value":4295032833}}, {"id":197,"raw":{"value":8}}, {"id":198,"raw":{"value":8}}, {"id":199,"raw":{"value":3}}]}}` // COMPANION RED-PROOF (observed): delete the three R-330 cases in parseSMART → this fails with // "187 Reported_Uncorrect must be carried (raw 1001); got ". Restored. func TestParseSMART_R330_CarriesTheThreeCounters(t *testing.T) { s := parseSMART([]byte(r330SATA)) if s.ReportedUncorrect == nil || *s.ReportedUncorrect != 1001 { t.Fatalf("187 Reported_Uncorrect must be carried (raw 1001); got %v", s.ReportedUncorrect) } // 188's raw value is vendor-packed on some drives (this one is 0x100010001): carried as reported, not truncated. if s.CommandTimeout == nil || *s.CommandTimeout != 4295032833 { t.Fatalf("188 Command_Timeout must be carried as the full raw value; got %v", s.CommandTimeout) } if s.UDMACRCErrors == nil || *s.UDMACRCErrors != 3 { t.Fatalf("199 UDMA_CRC_Error_Count must be carried (raw 3); got %v", s.UDMACRCErrors) } if s.PendingSectors == nil || *s.PendingSectors != 8 { t.Fatalf("the existing counters must be unchanged; pending=%v", s.PendingSectors) } } // A drive (or an NVMe device) that does not report the attributes leaves them nil, and the JSON // OMITS the keys — the receiver reads "unknown", never a measured zero. // // COMPANION RED-PROOF (observed): drop `,omitempty` from the three tags in hub.SmartSummary → this // fails with "an unreported attribute must be omitted, not sent: … reported_uncorrect …". Restored. func TestParseSMART_R330_AbsentIsOmittedNotZero(t *testing.T) { for name, raw := range map[string]string{ "sata without the three": `{"smart_status":{"passed":true},"ata_smart_attributes":{"table":[{"id":5,"raw":{"value":0}}]}}`, "nvme": `{"smart_status":{"passed":true},"nvme_smart_health_information_log":{"critical_warning":0,"media_errors":0,"percentage_used":3}}`, } { s := parseSMART([]byte(raw)) if s.ReportedUncorrect != nil || s.CommandTimeout != nil || s.UDMACRCErrors != nil { t.Fatalf("%s: unreported attributes must stay nil; got %v %v %v", name, s.ReportedUncorrect, s.CommandTimeout, s.UDMACRCErrors) } b, _ := json.Marshal(s) for _, k := range []string{"reported_uncorrect", "command_timeout", "udma_crc_errors"} { if strings.Contains(string(b), `"`+k+`"`) { t.Fatalf("%s: an unreported attribute must be omitted, not sent: %s", name, b) } } } }