Skip to content

Commit ba04bdf

Browse files
Add E2E tests for blob attachments across all 4 SDKs
Add blob attachment E2E tests for Node.js, Python, Go, and .NET SDKs. Each test sends a message with an inline base64-encoded PNG blob attachment and verifies the request is accepted by the replay proxy. - nodejs/test/e2e/session_config.test.ts: should accept blob attachments - python/e2e/test_session.py: test_should_accept_blob_attachments - go/internal/e2e/session_test.go: TestSessionBlobAttachment - dotnet/test/SessionTests.cs: Should_Accept_Blob_Attachments - test/snapshots/: request-only YAML snapshots for replay proxy Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 487299a commit ba04bdf

6 files changed

Lines changed: 120 additions & 0 deletions

File tree

dotnet/test/SessionTests.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,29 @@ public async Task DisposeAsync_From_Handler_Does_Not_Deadlock()
538538
await disposed.Task.WaitAsync(TimeSpan.FromSeconds(10));
539539
}
540540

541+
[Fact]
542+
public async Task Should_Accept_Blob_Attachments()
543+
{
544+
var session = await CreateSessionAsync();
545+
546+
await session.SendAsync(new MessageOptions
547+
{
548+
Prompt = "Describe this image",
549+
Attachments =
550+
[
551+
new UserMessageDataAttachmentsItemBlob
552+
{
553+
Data = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==",
554+
MimeType = "image/png",
555+
DisplayName = "test-pixel.png",
556+
},
557+
],
558+
});
559+
560+
// Just verify send doesn't throw — blob attachment support varies by runtime
561+
await session.DisposeAsync();
562+
}
563+
541564
private static async Task WaitForAsync(Func<bool> condition, TimeSpan timeout)
542565
{
543566
var deadline = DateTime.UtcNow + timeout;

go/internal/e2e/session_test.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -938,6 +938,48 @@ func TestSetModelWithReasoningEffort(t *testing.T) {
938938
}
939939
}
940940

941+
func TestSessionBlobAttachment(t *testing.T) {
942+
ctx := testharness.NewTestContext(t)
943+
client := ctx.NewClient()
944+
t.Cleanup(func() { client.ForceStop() })
945+
946+
if err := client.Start(t.Context()); err != nil {
947+
t.Fatalf("Failed to start client: %v", err)
948+
}
949+
950+
t.Run("should accept blob attachments", func(t *testing.T) {
951+
ctx.ConfigureForTest(t)
952+
953+
session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
954+
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
955+
})
956+
if err != nil {
957+
t.Fatalf("Failed to create session: %v", err)
958+
}
959+
960+
data := "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="
961+
mimeType := "image/png"
962+
displayName := "test-pixel.png"
963+
_, err = session.Send(t.Context(), copilot.MessageOptions{
964+
Prompt: "Describe this image",
965+
Attachments: []copilot.Attachment{
966+
{
967+
Type: copilot.Blob,
968+
Data: &data,
969+
MIMEType: &mimeType,
970+
DisplayName: &displayName,
971+
},
972+
},
973+
})
974+
if err != nil {
975+
t.Fatalf("Send with blob attachment failed: %v", err)
976+
}
977+
978+
// Just verify send doesn't error — blob attachment support varies by runtime
979+
session.Disconnect()
980+
})
981+
}
982+
941983
func getToolNames(exchange testharness.ParsedHttpExchange) []string {
942984
var names []string
943985
for _, tool := range exchange.Request.Tools {

nodejs/test/e2e/session_config.test.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,25 @@ describe("Session Configuration", async () => {
4343
}
4444
});
4545

46+
it("should accept blob attachments", async () => {
47+
const session = await client.createSession({ onPermissionRequest: approveAll });
48+
49+
await session.send({
50+
prompt: "Describe this image",
51+
attachments: [
52+
{
53+
type: "blob",
54+
data: "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==",
55+
mimeType: "image/png",
56+
displayName: "test-pixel.png",
57+
},
58+
],
59+
});
60+
61+
// Just verify send doesn't throw — blob attachment support varies by runtime
62+
await session.disconnect();
63+
});
64+
4665
it("should accept message attachments", async () => {
4766
await writeFile(join(workDir, "attached.txt"), "This file is attached");
4867

python/e2e/test_session.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,26 @@ def on_event(event):
569569
assert event.data.new_model == "gpt-4.1"
570570
assert event.data.reasoning_effort == "high"
571571

572+
async def test_should_accept_blob_attachments(self, ctx: E2ETestContext):
573+
session = await ctx.client.create_session(
574+
{"on_permission_request": PermissionHandler.approve_all}
575+
)
576+
577+
await session.send(
578+
"Describe this image",
579+
attachments=[
580+
{
581+
"type": "blob",
582+
"data": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==",
583+
"mimeType": "image/png",
584+
"displayName": "test-pixel.png",
585+
},
586+
],
587+
)
588+
589+
# Just verify send doesn't throw — blob attachment support varies by runtime
590+
await session.disconnect()
591+
572592

573593
def _get_system_message(exchange: dict) -> str:
574594
messages = exchange.get("request", {}).get("messages", [])
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
models:
2+
- claude-sonnet-4.5
3+
conversations:
4+
- messages:
5+
- role: system
6+
content: ${system}
7+
- role: user
8+
content: Describe this image
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
models:
2+
- claude-sonnet-4.5
3+
conversations:
4+
- messages:
5+
- role: system
6+
content: ${system}
7+
- role: user
8+
content: Describe this image

0 commit comments

Comments
 (0)