package backup import ( "crypto/sha256" "encoding/hex" "encoding/json" "log" "os" "path/filepath" "testing" ) func TestWriteAndReadLocalInfraBackup(t *testing.T) { tmpDir := t.TempDir() drive := filepath.Join(tmpDir, "mnt", "hdd_0") if err := os.MkdirAll(drive, 0755); err != nil { t.Fatal(err) } backupJSON := []byte(`{"customer_id":"test-123","domain":"test.hu","controller_version":"v0.21.0","timestamp":"2026-02-21T10:00:00Z"}`) logger := testLogger(t) WriteLocalInfraBackup(backupJSON, "test-123", "v0.21.0", "2026-02-21T10:00:00Z", []string{drive}, logger, false) // Verify files exist dir := InfraBackupDir(drive) if _, err := os.Stat(filepath.Join(dir, "backup.json")); err != nil { t.Fatalf("backup.json not found: %v", err) } if _, err := os.Stat(filepath.Join(dir, "metadata.json")); err != nil { t.Fatalf("metadata.json not found: %v", err) } // Read back data, meta, err := ReadLocalInfraBackup(drive) if err != nil { t.Fatalf("ReadLocalInfraBackup failed: %v", err) } if string(data) != string(backupJSON) { t.Errorf("backup data mismatch: got %s", string(data)) } if meta.SchemaVersion != 1 { t.Errorf("expected schema version 1, got %d", meta.SchemaVersion) } if meta.CustomerID != "test-123" { t.Errorf("expected customer_id test-123, got %s", meta.CustomerID) } if meta.ControllerVersion != "v0.21.0" { t.Errorf("expected controller version v0.21.0, got %s", meta.ControllerVersion) } // Verify checksum hash := sha256.Sum256(backupJSON) expected := hex.EncodeToString(hash[:]) if meta.Checksum != expected { t.Errorf("checksum mismatch: expected %s, got %s", expected, meta.Checksum) } } func TestReadLocalInfraBackup_ChecksumMismatch(t *testing.T) { tmpDir := t.TempDir() drive := filepath.Join(tmpDir, "mnt", "hdd_0") dir := InfraBackupDir(drive) if err := os.MkdirAll(dir, 0700); err != nil { t.Fatal(err) } // Write valid metadata with wrong checksum meta := InfraMetadata{SchemaVersion: 1, Checksum: "0000000000000000000000000000000000000000000000000000000000000000"} metaJSON, _ := json.Marshal(meta) os.WriteFile(filepath.Join(dir, "metadata.json"), metaJSON, 0600) os.WriteFile(filepath.Join(dir, "backup.json"), []byte(`{"test":true}`), 0600) _, _, err := ReadLocalInfraBackup(drive) if err == nil { t.Fatal("expected checksum mismatch error") } if got := err.Error(); !contains(got, "checksum mismatch") { t.Errorf("expected checksum mismatch error, got: %s", got) } } func TestReadLocalInfraBackup_SchemaVersionTooNew(t *testing.T) { tmpDir := t.TempDir() drive := filepath.Join(tmpDir, "mnt", "hdd_0") dir := InfraBackupDir(drive) if err := os.MkdirAll(dir, 0700); err != nil { t.Fatal(err) } meta := InfraMetadata{SchemaVersion: 999} metaJSON, _ := json.Marshal(meta) os.WriteFile(filepath.Join(dir, "metadata.json"), metaJSON, 0600) os.WriteFile(filepath.Join(dir, "backup.json"), []byte(`{}`), 0600) _, _, err := ReadLocalInfraBackup(drive) if err == nil { t.Fatal("expected schema version error") } if got := err.Error(); !contains(got, "newer than supported") { t.Errorf("expected schema version error, got: %s", got) } } func TestReadLocalInfraBackup_MissingFiles(t *testing.T) { tmpDir := t.TempDir() _, _, err := ReadLocalInfraBackup(tmpDir) if err == nil { t.Fatal("expected error for missing files") } } func TestWriteLocalInfraBackup_MultipleDrives(t *testing.T) { tmpDir := t.TempDir() drives := []string{ filepath.Join(tmpDir, "drive1"), filepath.Join(tmpDir, "drive2"), filepath.Join(tmpDir, "drive3_fail"), // won't be created as a dir, but MkdirAll should handle it } for _, d := range drives { os.MkdirAll(d, 0755) } backupJSON := []byte(`{"test":"multi"}`) logger := testLogger(t) WriteLocalInfraBackup(backupJSON, "multi-test", "v1.0", "2026-01-01T00:00:00Z", drives, logger, false) // All 3 should succeed for _, d := range drives { data, _, err := ReadLocalInfraBackup(d) if err != nil { t.Errorf("drive %s: read failed: %v", d, err) continue } if string(data) != string(backupJSON) { t.Errorf("drive %s: data mismatch", d) } } } func TestWriteLocalInfraBackup_NoDrives(t *testing.T) { logger := testLogger(t) // Should not panic WriteLocalInfraBackup([]byte(`{}`), "test", "v1.0", "2026-01-01T00:00:00Z", nil, logger, false) } func contains(s, substr string) bool { return len(s) >= len(substr) && (s == substr || len(s) > 0 && containsStr(s, substr)) } func containsStr(s, substr string) bool { for i := 0; i+len(substr) <= len(s); i++ { if s[i:i+len(substr)] == substr { return true } } return false } func testLogger(t *testing.T) *log.Logger { return log.New(os.Stderr, "[test] ", log.LstdFlags) }