File size: 3,192 Bytes
8d3471e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
package devcapture

import (
	"io"
	"strings"
	"testing"
	"unicode/utf8"
)

func TestNewFromEnvDefaults(t *testing.T) {
	t.Setenv("DS2API_DEV_PACKET_CAPTURE_LIMIT", "")
	t.Setenv("DS2API_DEV_PACKET_CAPTURE_MAX_BODY_BYTES", "")
	t.Setenv("VERCEL", "")
	t.Setenv("NOW_REGION", "")

	s := NewFromEnv()
	if s.Limit() != 20 {
		t.Fatalf("expected default limit 20, got %d", s.Limit())
	}
	if s.MaxBodyBytes() != 5*1024*1024 {
		t.Fatalf("expected default max body bytes 5MB, got %d", s.MaxBodyBytes())
	}
}

func TestNewFromEnvHonorsOverrides(t *testing.T) {
	t.Setenv("DS2API_DEV_PACKET_CAPTURE_LIMIT", "7")
	t.Setenv("DS2API_DEV_PACKET_CAPTURE_MAX_BODY_BYTES", "8192")
	t.Setenv("VERCEL", "")
	t.Setenv("NOW_REGION", "")
	s := NewFromEnv()
	if s.Limit() != 7 {
		t.Fatalf("expected override limit 7, got %d", s.Limit())
	}
	if s.MaxBodyBytes() != 8192 {
		t.Fatalf("expected override max body bytes 8192, got %d", s.MaxBodyBytes())
	}
}

func TestStorePushKeepsNewestWithinLimit(t *testing.T) {
	s := &Store{enabled: true, limit: 2, maxBodyBytes: 1024}
	for i := 0; i < 3; i++ {
		session := s.Start("test", "http://x", "", map[string]any{"seq": i})
		if session == nil {
			t.Fatal("expected session")
		}
		rc := session.WrapBody(io.NopCloser(strings.NewReader("ok")), 200)
		_, _ = io.ReadAll(rc)
		_ = rc.Close()
	}
	items := s.Snapshot()
	if len(items) != 2 {
		t.Fatalf("expected 2 items, got %d", len(items))
	}
	if !strings.Contains(items[0].RequestBody, `"seq":2`) {
		t.Fatalf("expected newest first, got %#v", items[0].RequestBody)
	}
	if !strings.Contains(items[1].RequestBody, `"seq":1`) {
		t.Fatalf("expected second newest, got %#v", items[1].RequestBody)
	}
}

func TestWrapBodyTruncatesByLimit(t *testing.T) {
	s := &Store{enabled: true, limit: 5, maxBodyBytes: 4}
	session := s.Start("test", "http://x", "acc1", map[string]any{"x": 1})
	if session == nil {
		t.Fatal("expected session")
	}
	rc := session.WrapBody(io.NopCloser(strings.NewReader("abcdef")), 200)
	_, _ = io.ReadAll(rc)
	_ = rc.Close()

	items := s.Snapshot()
	if len(items) != 1 {
		t.Fatalf("expected 1 item, got %d", len(items))
	}
	if items[0].ResponseBody != "abcd" {
		t.Fatalf("expected truncated body, got %q", items[0].ResponseBody)
	}
	if !items[0].ResponseTruncated {
		t.Fatal("expected truncated flag true")
	}
	if items[0].AccountID != "acc1" {
		t.Fatalf("expected account id, got %q", items[0].AccountID)
	}
}

func TestWrapBodyTruncatesUTF8WithoutBreakingRune(t *testing.T) {
	s := &Store{enabled: true, limit: 5, maxBodyBytes: 5}
	session := s.Start("test", "http://x", "acc1", map[string]any{"x": 1})
	if session == nil {
		t.Fatal("expected session")
	}
	rc := session.WrapBody(io.NopCloser(strings.NewReader("😀xy")), 200)
	_, _ = io.ReadAll(rc)
	_ = rc.Close()

	items := s.Snapshot()
	if len(items) != 1 {
		t.Fatalf("expected 1 item, got %d", len(items))
	}
	if !utf8.ValidString(items[0].ResponseBody) {
		t.Fatalf("expected valid utf-8 response body, got %q", items[0].ResponseBody)
	}
	if items[0].ResponseBody != "😀x" {
		t.Fatalf("expected rune-safe truncation, got %q", items[0].ResponseBody)
	}
	if !items[0].ResponseTruncated {
		t.Fatal("expected truncated flag true")
	}
}