package isphere import ( "context" "crypto/cipher" "crypto/des" "encoding/base64" "testing" ) func TestEncryptedPacketLogSourceReturnsNormalizedMessages(t *testing.T) { plaintext := `-------------------------------------------------------------------------------------------------------------------------------------------- 2026/7/7 15:30:07 redacted FILE_TRANSFER_CANCEL ` source := EncryptedPacketLogSource{Lines: []string{encryptPacketLineForTest(t, plaintext)}} got, err := source.ReceiveMessages(context.Background(), ReceiveMessagesQuery{Limit: 10}) if err != nil { t.Fatalf("ReceiveMessages returned error: %v", err) } if len(got.Messages) != 1 { t.Fatalf("message count = %d, want 1", len(got.Messages)) } msg := got.Messages[0] if msg.ID != "msg-1" || msg.Text != "redacted" || msg.Subject != "FILE_TRANSFER_CANCEL" { t.Fatalf("unexpected message content: %+v", msg) } if msg.ConversationID != "sender@imopenfire1-lanzhou|receiver@imopenfire1-lanzhou" { t.Fatalf("conversation id = %q", msg.ConversationID) } if msg.SenderID != "sender@imopenfire1-lanzhou" || msg.ReceiverID != "receiver@imopenfire1-lanzhou" { t.Fatalf("sender/receiver = %q/%q", msg.SenderID, msg.ReceiverID) } if msg.Timestamp != "1783423807000" || msg.ReceiptID != "receipt-1" || !msg.Read { t.Fatalf("metadata = %+v", msg) } } func TestEncryptedPacketLogSourceFiltersByConversationAndQuery(t *testing.T) { first := `-------------------------------------------------------------------------------------------------------------------------------------------- 2026/7/7 15:30:07 alpha status update TASK_UPDATE ` second := `-------------------------------------------------------------------------------------------------------------------------------------------- 2026/7/7 15:31:07 beta budget redacted-report.docx FILE_TRANSFER_CANCEL ` source := EncryptedPacketLogSource{Lines: []string{ encryptPacketLineForTest(t, first), encryptPacketLineForTest(t, second), }} got, err := source.ReceiveMessages(context.Background(), ReceiveMessagesQuery{ ConversationID: "project-room@conference.imopenfire1-lanzhou|sender@imopenfire1-lanzhou", Query: "BUDGET", Limit: 10, }) if err != nil { t.Fatalf("ReceiveMessages returned error: %v", err) } if len(got.Messages) != 1 { t.Fatalf("message count = %d, want 1: %+v", len(got.Messages), got.Messages) } if got.Messages[0].ID != "msg-beta" { t.Fatalf("message id = %q, want msg-beta", got.Messages[0].ID) } empty, err := source.ReceiveMessages(context.Background(), ReceiveMessagesQuery{ ConversationID: "project-room@conference.imopenfire1-lanzhou|sender@imopenfire1-lanzhou", Query: "alpha", Limit: 10, }) if err != nil { t.Fatalf("ReceiveMessages returned error for empty query: %v", err) } if len(empty.Messages) != 0 { t.Fatalf("empty query returned %+v, want none", empty.Messages) } } func TestEncryptedPacketLogSourceFiltersBySince(t *testing.T) { first := `-------------------------------------------------------------------------------------------------------------------------------------------- 2026/7/7 15:30:07 before threshold TASK_UPDATE ` second := `-------------------------------------------------------------------------------------------------------------------------------------------- 2026/7/7 15:31:07 after threshold TASK_UPDATE ` source := EncryptedPacketLogSource{Lines: []string{ encryptPacketLineForTest(t, first), encryptPacketLineForTest(t, second), }} got, err := source.ReceiveMessages(context.Background(), ReceiveMessagesQuery{ Since: "2026-07-07T11:31:00Z", Limit: 10, }) if err != nil { t.Fatalf("ReceiveMessages returned error: %v", err) } if len(got.Messages) != 1 || got.Messages[0].ID != "msg-after" { t.Fatalf("messages = %+v, want only msg-after", got.Messages) } _, err = source.ReceiveMessages(context.Background(), ReceiveMessagesQuery{Since: "not-a-time"}) if err == nil { t.Fatalf("ReceiveMessages accepted invalid since") } } func encryptPacketLineForTest(t *testing.T, plaintext string) string { t.Helper() block, err := des.NewCipher([]byte("hyhccdtm")) if err != nil { t.Fatalf("NewCipher: %v", err) } plain := padPacketLineForTest([]byte(plaintext), des.BlockSize) ciphertext := make([]byte, len(plain)) iv := []byte{0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF} cipher.NewCBCEncrypter(block, iv).CryptBlocks(ciphertext, plain) return base64.StdEncoding.EncodeToString(ciphertext) } func padPacketLineForTest(data []byte, blockSize int) []byte { pad := blockSize - len(data)%blockSize out := append([]byte(nil), data...) for i := 0; i < pad; i++ { out = append(out, byte(pad)) } return out }