File size: 2,293 Bytes
afa0cbf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
use pretty_assertions::assert_eq;

use super::*;

/// Debug output redacts attachment bytes in requests and results.
#[test]
fn attachment_debug_output_redacts_bytes() {
    let request = UploadRequest {
        file_name: Some("image.png".to_string()),
        data: b"secret".to_vec(),
    };
    let result = UploadResult::Inline {
        bytes: b"secret".to_vec(),
    };

    assert_eq!(
        (format!("{request:?}"), format!("{result:?}")),
        (
            r#"UploadRequest { file_name: Some("image.png"), data: "<redacted>" }"#.to_string(),
            r#"Inline { bytes: "<redacted>" }"#.to_string(),
        )
    );
}

/// Debug output redacts credential-bearing file URLs in resolved metadata.
#[test]
fn attachment_metadata_debug_output_redacts_file_url() {
    let metadata = AttachmentMetadata {
        file_url: Some("https://attachments.test/file?signed=secret".to_string()),
        ..AttachmentMetadata::default()
    };

    let debug = format!("{metadata:?}");

    assert!(!debug.contains("signed=secret"));
    assert!(debug.contains("<redacted>"));
}

/// The inline store preserves PNG and JPEG attachment bytes.
#[tokio::test]
async fn inline_store_preserves_image_bytes() {
    let cases: [(&str, &[u8]); 2] = [
        ("image.png", b"\x89PNG\r\n\x1a\n"),
        ("image.jpg", b"\xff\xd8\xff\xe0JFIF\x00\xff\xd9"),
    ];

    for (file_name, data) in cases {
        let attachment = InlineAttachmentStore
            .upload(UploadRequest {
                file_name: Some(file_name.to_string()),
                data: data.to_vec(),
            })
            .await
            .expect("inline attachment");
        let UploadResult::Inline { bytes } = attachment else {
            panic!("inline store returned a file reference");
        };

        assert_eq!(bytes, data);
    }
}

/// The inline store reports file references as missing because it never uploads them.
#[tokio::test]
async fn inline_store_cannot_resolve_file_references() {
    let error = InlineAttachmentStore
        .resolve(ResolveRequest {
            file_id: "file_123",
            download_url_ttl: None,
        })
        .await
        .expect_err("inline store cannot resolve file references");

    assert_eq!(error.kind(), AttachmentStoreErrorKind::NotFound);
}