Skip to content

Commit 9d3a7dc

Browse files
fix(rest): add Retrofit2SyncCall.execute to RestService in RestEventService (#1480) (#1481)
* test(rest): add a test to demonstrate that RestEventService.sendEvent is failing to make the RestService.recordEvent api call * fix(rest): add Retrofit2SyncCall.execute to RestService in RestEventService (cherry picked from commit d3c1833) Co-authored-by: Kiran Godishala <[email protected]>
1 parent a410556 commit 9d3a7dc

File tree

4 files changed

+123
-1
lines changed

4 files changed

+123
-1
lines changed

echo-rest/echo-rest.gradle

+1
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,5 @@ dependencies {
3131
testImplementation project(':echo-test')
3232
testImplementation "com.github.tomakehurst:wiremock-jre8"
3333
testImplementation "org.springframework.boot:spring-boot-starter-test"
34+
testImplementation "com.squareup.retrofit2:retrofit-mock"
3435
}

echo-rest/src/main/java/com/netflix/spinnaker/echo/events/RestEventService.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import com.netflix.spinnaker.echo.config.RestProperties;
2020
import com.netflix.spinnaker.echo.config.RestUrls;
2121
import com.netflix.spinnaker.kork.core.RetrySupport;
22+
import com.netflix.spinnaker.kork.retrofit.Retrofit2SyncCall;
2223
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
2324
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
2425
import java.time.Duration;
@@ -55,7 +56,7 @@ public void sendEventWithCircuitBreaker(
5556
*/
5657
public void sendEvent(Map<String, Object> event, RestUrls.Service service) {
5758
retrySupport.retry(
58-
() -> service.getClient().recordEvent(event),
59+
() -> Retrofit2SyncCall.execute(service.getClient().recordEvent(event)),
5960
service.getConfig().getRetryCount(),
6061
Duration.ofMillis(200),
6162
false);

echo-rest/src/test/java/com/netflix/spinnaker/echo/events/RestEventListenerTest.java

+5
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,15 @@
3131
import java.util.HashMap;
3232
import java.util.List;
3333
import java.util.Map;
34+
import okhttp3.MediaType;
35+
import okhttp3.ResponseBody;
3436
import org.junit.jupiter.api.Assertions;
3537
import org.junit.jupiter.api.BeforeEach;
3638
import org.junit.jupiter.api.Test;
3739
import org.junit.jupiter.api.extension.ExtendWith;
3840
import org.mockito.Mockito;
3941
import org.mockito.junit.jupiter.MockitoExtension;
42+
import retrofit2.mock.Calls;
4043

4144
@ExtendWith(MockitoExtension.class)
4245
class RestEventListenerTest {
@@ -221,6 +224,8 @@ void exceptionInSendingEventToOneHostDoesNotAffectSecondHost() {
221224
Map<String, Object> expectedEvent = listener.getMapper().convertValue(event, Map.class);
222225

223226
Mockito.when(restService.recordEvent(expectedEvent)).thenThrow(new RuntimeException());
227+
Mockito.when(restService2.recordEvent(expectedEvent))
228+
.thenReturn(Calls.response(ResponseBody.create(MediaType.parse("application/json"), "{}")));
224229

225230
listener.processEvent(event);
226231

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/*
2+
* Copyright 2025 OpsMx, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.netflix.spinnaker.echo.events;
18+
19+
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
20+
import static com.github.tomakehurst.wiremock.client.WireMock.post;
21+
import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor;
22+
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
23+
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
24+
import static com.github.tomakehurst.wiremock.client.WireMock.verify;
25+
26+
import com.fasterxml.jackson.databind.ObjectMapper;
27+
import com.github.tomakehurst.wiremock.WireMockServer;
28+
import com.github.tomakehurst.wiremock.client.WireMock;
29+
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
30+
import com.netflix.spinnaker.echo.api.events.Event;
31+
import com.netflix.spinnaker.echo.config.RestProperties;
32+
import com.netflix.spinnaker.echo.config.RestUrls;
33+
import com.netflix.spinnaker.echo.rest.RestService;
34+
import com.netflix.spinnaker.echo.util.RetrofitUtils;
35+
import com.netflix.spinnaker.kork.core.RetrySupport;
36+
import com.netflix.spinnaker.kork.retrofit.ErrorHandlingExecutorCallAdapterFactory;
37+
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
38+
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
39+
import java.util.Map;
40+
import okhttp3.OkHttpClient;
41+
import org.junit.jupiter.api.AfterAll;
42+
import org.junit.jupiter.api.BeforeAll;
43+
import org.junit.jupiter.api.Test;
44+
import retrofit2.Retrofit;
45+
import retrofit2.converter.jackson.JacksonConverterFactory;
46+
47+
public class RestEventServiceTest {
48+
private static Map<String, Object> eventMap;
49+
private static RestEventService restEventService;
50+
private static RestUrls.Service service;
51+
52+
static WireMockServer wireMockServer;
53+
static int port;
54+
static String baseUrl = "http://localhost:PORT/api";
55+
56+
@BeforeAll
57+
static void setup() {
58+
wireMockServer = new WireMockServer(WireMockConfiguration.options().dynamicPort());
59+
wireMockServer.start();
60+
port = wireMockServer.port();
61+
WireMock.configureFor("localhost", port);
62+
63+
stubFor(post(urlEqualTo("/api/")).willReturn(aResponse().withStatus(200)));
64+
65+
baseUrl = baseUrl.replaceFirst("PORT", String.valueOf(port));
66+
67+
// Create the RestService
68+
RestService restService =
69+
new Retrofit.Builder()
70+
.baseUrl(RetrofitUtils.getBaseUrl(baseUrl))
71+
.client(new OkHttpClient())
72+
.addCallAdapterFactory(ErrorHandlingExecutorCallAdapterFactory.getInstance())
73+
.addConverterFactory(JacksonConverterFactory.create())
74+
.build()
75+
.create(RestService.class);
76+
77+
// Create a custom configuration for a CircuitBreaker
78+
CircuitBreakerConfig circuitBreakerConfig =
79+
CircuitBreakerConfig.custom()
80+
.failureRateThreshold(1)
81+
.permittedNumberOfCallsInHalfOpenState(1)
82+
.minimumNumberOfCalls(1)
83+
.build();
84+
85+
// Create a CircuitBreakerRegistry with a custom configuration
86+
CircuitBreakerRegistry circuitBreakerRegistry = CircuitBreakerRegistry.of(circuitBreakerConfig);
87+
88+
// Get the CircuitBreaker from the CircuitBreakerRegistry with a custom configuration
89+
circuitBreakerRegistry.circuitBreaker("circuitBreakerTest", circuitBreakerConfig);
90+
91+
restEventService = new RestEventService(new RetrySupport(), circuitBreakerRegistry);
92+
93+
Event event = new Event();
94+
event.setContent(Map.of("uno", "dos"));
95+
ObjectMapper mapper = new ObjectMapper();
96+
eventMap = mapper.convertValue(event, Map.class);
97+
98+
service =
99+
RestUrls.Service.builder()
100+
.client(restService)
101+
.config(new RestProperties.RestEndpointConfiguration())
102+
.build();
103+
}
104+
105+
@AfterAll
106+
static void cleanup() {
107+
wireMockServer.stop();
108+
}
109+
110+
@Test
111+
void testSendEvent() {
112+
restEventService.sendEvent(eventMap, service);
113+
verify(1, postRequestedFor(urlEqualTo("/api/")));
114+
}
115+
}

0 commit comments

Comments
 (0)