66
77package io .kroxylicious .proxy .filter .simpletransform ;
88
9+ import java .io .IOException ;
910import java .nio .ByteBuffer ;
1011import java .nio .charset .StandardCharsets ;
12+ import java .nio .file .Files ;
13+ import java .nio .file .Path ;
14+ import java .nio .file .Paths ;
1115import java .util .Collection ;
1216import java .util .Locale ;
1317import java .util .Objects ;
3539import org .junit .jupiter .api .BeforeEach ;
3640import org .junit .jupiter .api .Test ;
3741import org .junit .jupiter .api .extension .ExtendWith ;
42+ import org .junit .jupiter .api .io .TempDir ;
3843import org .mockito .ArgumentCaptor ;
3944import org .mockito .Captor ;
4045import org .mockito .Mock ;
4146import org .mockito .junit .jupiter .MockitoExtension ;
4247import org .mockito .stubbing .Answer ;
4348
49+ import com .fasterxml .jackson .databind .ObjectMapper ;
50+
51+ import io .kroxylicious .proxy .config .ConfigParser ;
4452import io .kroxylicious .proxy .filter .FilterContext ;
4553import io .kroxylicious .proxy .filter .FilterFactoryContext ;
4654import io .kroxylicious .proxy .filter .ResponseFilterResult ;
@@ -85,6 +93,8 @@ class FetchResponseTransformationFilterTest {
8593 @ Captor
8694 private ArgumentCaptor <ApiMessage > apiMessageCaptor ;
8795
96+ private static final ObjectMapper MAPPER = ConfigParser .createObjectMapper ();
97+
8898 @ BeforeEach
8999 @ SuppressWarnings ("unchecked" )
90100 void setUp () {
@@ -122,11 +132,66 @@ void testFactory() {
122132 assertThat (factory .createFilter (constructContext , config )).isInstanceOf (FetchResponseTransformationFilter .class );
123133 }
124134
135+ @ Test
136+ void shouldRequireConfigForReplacingFilter () {
137+ // Given
138+ FetchResponseTransformation factory = new FetchResponseTransformation ();
139+
140+ // When
141+ // Then
142+ assertThatThrownBy (() -> factory .initialize (null , null )).isInstanceOf (PluginConfigurationException .class )
143+ .hasMessage (FetchResponseTransformation .class .getSimpleName () + " requires configuration, but config object is null" );
144+ }
145+
146+ @ Test
147+ void shouldConstructReplacingFilter () {
148+ FetchResponseTransformation factory = new FetchResponseTransformation ();
149+ FilterFactoryContext constructContext = mock (FilterFactoryContext .class );
150+ doReturn (new Replacing ()).when (constructContext ).pluginInstance (any (), any ());
151+ FetchResponseTransformation .Config config = new FetchResponseTransformation .Config (Replacing .class .getName (),
152+ new Replacing .Config (null , "foo" , "bar" , null ));
153+ assertThat (factory .createFilter (constructContext , config )).isInstanceOf (FetchResponseTransformationFilter .class );
154+ }
155+
156+ @ Test
157+ void shouldConstructReplacingFilterWithPath (@ TempDir Path tempDir ) throws IOException {
158+ Path replamventValuePath = Files .createFile (Path .of (tempDir .toAbsolutePath ().toString (), "replacement-value.txt" ));
159+ Files .writeString (replamventValuePath , "bar" , StandardCharsets .UTF_8 );
160+ FetchResponseTransformation factory = new FetchResponseTransformation ();
161+ FilterFactoryContext constructContext = mock (FilterFactoryContext .class );
162+ doReturn (new Replacing ()).when (constructContext ).pluginInstance (any (), any ());
163+ FetchResponseTransformation .Config config = new FetchResponseTransformation .Config (Replacing .class .getName (),
164+ new Replacing .Config (null , "foo" , null , replamventValuePath ));
165+ assertThat (factory .createFilter (constructContext , config )).isInstanceOf (FetchResponseTransformationFilter .class );
166+ }
167+
168+ @ Test
169+ void shouldConstructReplacingFilterWithPathConfig (@ TempDir Path tempDir ) throws IOException {
170+ // Given
171+ Path replamventValuePath = Files .createFile (Path .of (tempDir .toAbsolutePath ().toString (), "replacement-value.txt" ));
172+ Path valuePath = Files .writeString (replamventValuePath , "bar" , StandardCharsets .UTF_8 );
173+
174+ FetchResponseTransformation .Config config = new FetchResponseTransformation .Config (Replacing .class .getName (),
175+ new Replacing .Config (null , "foo" , null , Paths .get (valuePath .toUri ())));
176+ // toUri called so the expected and actual match see
177+ // https://github.com/FasterXML/jackson-databind/blob/099481bf725afd11dfd4f3c23eed9465fa3391da/src/main/java/com/fasterxml/jackson/databind/ext/NioPathDeserializer.java#L65
178+
179+ String snippet = MAPPER .writeValueAsString (config ).stripTrailing ();
180+
181+ // When
182+ FetchResponseTransformation .Config actual = MAPPER .readValue (snippet , FetchResponseTransformation .Config .class );
183+
184+ // Then
185+ assertThat (actual )
186+ .isInstanceOf (FetchResponseTransformation .Config .class )
187+ .isEqualTo (config );
188+ }
189+
125190 @ Test
126191 void filterHandlesPreV13ResponseBasedOnTopicNames () throws Exception {
127192
128193 var fetchResponse = new FetchResponseData ();
129- fetchResponse .responses ().add (createFetchableTopicResponseWithOneRecord (RECORD_KEY , ORIGINAL_RECORD_VALUE ).setTopic (TOPIC_NAME )); // Version 12
194+ fetchResponse .responses ().add (createFetchableTopicResponseWithOneRecord ().setTopic (TOPIC_NAME )); // Version 12
130195
131196 var stage = filter .onFetchResponse (fetchResponse .apiKey (), new ResponseHeaderData (), fetchResponse , context );
132197 assertThat (stage ).isCompleted ();
@@ -147,7 +212,7 @@ void filterHandlesPreV13ResponseBasedOnTopicNames() throws Exception {
147212 void filterHandlesV13OrHigherResponseBasedOnTopicIds () throws Exception {
148213
149214 var fetchResponse = new FetchResponseData ();
150- fetchResponse .responses ().add (createFetchableTopicResponseWithOneRecord (RECORD_KEY , ORIGINAL_RECORD_VALUE ).setTopicId (TOPIC_ID ));
215+ fetchResponse .responses ().add (createFetchableTopicResponseWithOneRecord ().setTopicId (TOPIC_ID ));
151216
152217 var metadataResponse = new MetadataResponseData ();
153218 metadataResponse .topics ().add (new MetadataResponseData .MetadataResponseTopic ().setTopicId (TOPIC_ID ).setName (TOPIC_NAME ));
@@ -185,7 +250,7 @@ void filterHandlesMetadataRequestError() {
185250
186251 var fetchResponse = new FetchResponseData ();
187252 // Version 13 switched to topic id rather than topic names.
188- fetchResponse .responses ().add (createFetchableTopicResponseWithOneRecord (RECORD_KEY , ORIGINAL_RECORD_VALUE ).setTopicId (TOPIC_ID ));
253+ fetchResponse .responses ().add (createFetchableTopicResponseWithOneRecord ().setTopicId (TOPIC_ID ));
189254
190255 var metadataResponse = new MetadataResponseData ();
191256 metadataResponse .topics ().add (new MetadataResponseData .MetadataResponseTopic ().setTopicId (TOPIC_ID ).setName (TOPIC_NAME ));
@@ -212,19 +277,19 @@ private Stream<Record> responseToRecordStream(FetchResponseData filteredResponse
212277 }
213278
214279 @ NonNull
215- private static FetchableTopicResponse createFetchableTopicResponseWithOneRecord (String key , String value ) {
280+ private static FetchableTopicResponse createFetchableTopicResponseWithOneRecord () {
216281 var fetchableTopicResponse = new FetchableTopicResponse ();
217282 var partitionData1 = new PartitionData ();
218- partitionData1 .setRecords (buildOneRecord (key , value ));
283+ partitionData1 .setRecords (buildOneRecord ());
219284 fetchableTopicResponse .partitions ().add (partitionData1 );
220285 return fetchableTopicResponse ;
221286 }
222287
223- private static MemoryRecords buildOneRecord (String key , String value ) {
288+ private static MemoryRecords buildOneRecord () {
224289 ByteBuffer buffer = ByteBuffer .allocate (1024 );
225290 try (MemoryRecordsBuilder builder = MemoryRecords .builder (buffer , RecordBatch .CURRENT_MAGIC_VALUE ,
226291 Compression .NONE , TimestampType .CREATE_TIME , 0L , System .currentTimeMillis ())) {
227- builder .append (0L , key . getBytes (), value .getBytes ());
292+ builder .append (0L , FetchResponseTransformationFilterTest . RECORD_KEY . getBytes (), FetchResponseTransformationFilterTest . ORIGINAL_RECORD_VALUE .getBytes ());
228293 return builder .build ();
229294 }
230295 }
0 commit comments