@@ -18,6 +18,7 @@ package loader
1818
1919import (
2020 "context"
21+ "strings"
2122 "testing"
2223
2324 "sigs.k8s.io/controller-runtime/pkg/log"
5253 _ requesthandling.ResponseBodyRequirement = & fakeResponsePlugin {}
5354)
5455
56+ // fakeChunkPlugin declares BodyChunked and implements ChunkProcessor.
57+ type fakeChunkPlugin struct {
58+ fakeResponsePlugin
59+ }
60+
61+ func (p * fakeChunkPlugin ) ProcessResponseChunk (_ context.Context , _ * plugin.CycleState , chunk []byte , _ bool ) ([]byte , error ) {
62+ return chunk , nil
63+ }
64+
65+ var _ requesthandling.ChunkProcessor = & fakeChunkPlugin {}
66+
67+ // badChunkedPlugin declares BodyChunked but does NOT implement ChunkProcessor.
68+ type badChunkedPlugin struct {
69+ fakeResponsePlugin
70+ }
71+
5572type legacyResponsePlugin struct {
5673 name string
5774}
@@ -71,10 +88,13 @@ func modePtr(m requesthandling.ResponseBodyMode) *requesthandling.ResponseBodyMo
7188func TestComputeResponseBuffering (t * testing.T ) {
7289 logger := log .FromContext (logutil .NewTestLoggerIntoContext (context .Background ()))
7390
91+ chunkedMode := modePtr (requesthandling .BodyChunked )
92+
7493 tests := []struct {
75- name string
76- plugins []requesthandling.ResponseProcessor
77- wantBuffering bool
94+ name string
95+ plugins []requesthandling.ResponseProcessor
96+ wantBuffering bool
97+ wantChunkCount int
7898 }{
7999 {
80100 name : "no response plugins" ,
@@ -90,11 +110,12 @@ func TestComputeResponseBuffering(t *testing.T) {
90110 wantBuffering : false ,
91111 },
92112 {
93- name : "all BodyChunked" ,
113+ name : "BodyChunked with ChunkProcessor " ,
94114 plugins : []requesthandling.ResponseProcessor {
95- & fakeResponsePlugin {name : "a " , mode : modePtr ( requesthandling . BodyChunked ) },
115+ & fakeChunkPlugin { fakeResponsePlugin {name : "chunker " , mode : chunkedMode } },
96116 },
97- wantBuffering : false ,
117+ wantBuffering : false ,
118+ wantChunkCount : 1 ,
98119 },
99120 {
100121 name : "one BodyFull forces buffering" ,
@@ -114,18 +135,20 @@ func TestComputeResponseBuffering(t *testing.T) {
114135 {
115136 name : "mixed: BodyChunked + legacy forces buffering" ,
116137 plugins : []requesthandling.ResponseProcessor {
117- & fakeResponsePlugin {name : "a" , mode : modePtr ( requesthandling . BodyChunked ) },
138+ & fakeChunkPlugin { fakeResponsePlugin {name : "a" , mode : chunkedMode } },
118139 & legacyResponsePlugin {name : "legacy" },
119140 },
120- wantBuffering : true ,
141+ wantBuffering : true ,
142+ wantChunkCount : 1 ,
121143 },
122144 {
123145 name : "mixed: BodyNotNeeded + BodyChunked — no buffering" ,
124146 plugins : []requesthandling.ResponseProcessor {
125147 & fakeResponsePlugin {name : "a" , mode : modePtr (requesthandling .BodyNotNeeded )},
126- & fakeResponsePlugin {name : "b" , mode : modePtr ( requesthandling . BodyChunked ) },
148+ & fakeChunkPlugin { fakeResponsePlugin {name : "b" , mode : chunkedMode } },
127149 },
128- wantBuffering : false ,
150+ wantBuffering : false ,
151+ wantChunkCount : 1 ,
129152 },
130153 }
131154
@@ -136,35 +159,75 @@ func TestComputeResponseBuffering(t *testing.T) {
136159 ResponsePlugins : tc .plugins ,
137160 },
138161 }
139- computeResponseBuffering (profiles , logger )
162+ if err := computeResponseBuffering (profiles , logger ); err != nil {
163+ t .Fatalf ("computeResponseBuffering() unexpected error: %v" , err )
164+ }
140165 if profiles ["test" ].NeedsResponseBuffering != tc .wantBuffering {
141166 t .Errorf ("NeedsResponseBuffering = %v, want %v" , profiles ["test" ].NeedsResponseBuffering , tc .wantBuffering )
142167 }
168+ if got := len (profiles ["test" ].ChunkProcessors ); got != tc .wantChunkCount {
169+ t .Errorf ("ChunkProcessors count = %d, want %d" , got , tc .wantChunkCount )
170+ }
143171 })
144172 }
145173}
146174
175+ func TestComputeResponseBuffering_BodyChunkedWithoutChunkProcessor (t * testing.T ) {
176+ logger := log .FromContext (logutil .NewTestLoggerIntoContext (context .Background ()))
177+
178+ profiles := map [string ]* requesthandling.Profile {
179+ "test" : {
180+ ResponsePlugins : []requesthandling.ResponseProcessor {
181+ & badChunkedPlugin {fakeResponsePlugin {name : "bad" , mode : modePtr (requesthandling .BodyChunked )}},
182+ },
183+ },
184+ }
185+
186+ err := computeResponseBuffering (profiles , logger )
187+ if err == nil {
188+ t .Fatal ("expected error for BodyChunked plugin without ChunkProcessor" )
189+ }
190+ if ! strings .Contains (err .Error (), "does not implement ChunkProcessor" ) {
191+ t .Errorf ("error message should mention ChunkProcessor, got: %v" , err )
192+ }
193+ }
194+
147195func TestComputeResponseBuffering_MultipleProfiles (t * testing.T ) {
148196 logger := log .FromContext (logutil .NewTestLoggerIntoContext (context .Background ()))
149197
198+ chunkedMode := modePtr (requesthandling .BodyChunked )
199+
150200 profiles := map [string ]* requesthandling.Profile {
151201 "streaming" : {
152202 ResponsePlugins : []requesthandling.ResponseProcessor {
153203 & fakeResponsePlugin {name : "headers-only" , mode : modePtr (requesthandling .BodyNotNeeded )},
154204 },
155205 },
206+ "chunked" : {
207+ ResponsePlugins : []requesthandling.ResponseProcessor {
208+ & fakeChunkPlugin {fakeResponsePlugin {name : "meter" , mode : chunkedMode }},
209+ },
210+ },
156211 "full-body" : {
157212 ResponsePlugins : []requesthandling.ResponseProcessor {
158213 & fakeResponsePlugin {name : "translator" , mode : modePtr (requesthandling .BodyFull )},
159214 },
160215 },
161216 }
162217
163- computeResponseBuffering (profiles , logger )
218+ if err := computeResponseBuffering (profiles , logger ); err != nil {
219+ t .Fatalf ("unexpected error: %v" , err )
220+ }
164221
165222 if profiles ["streaming" ].NeedsResponseBuffering {
166223 t .Error ("streaming profile should not need buffering" )
167224 }
225+ if profiles ["chunked" ].NeedsResponseBuffering {
226+ t .Error ("chunked profile should not need buffering" )
227+ }
228+ if len (profiles ["chunked" ].ChunkProcessors ) != 1 {
229+ t .Errorf ("chunked profile should have 1 ChunkProcessor, got %d" , len (profiles ["chunked" ].ChunkProcessors ))
230+ }
168231 if ! profiles ["full-body" ].NeedsResponseBuffering {
169232 t .Error ("full-body profile should need buffering" )
170233 }
0 commit comments