mirror of
https://github.com/google/nomulus
synced 2026-09-20 15:04:24 +00:00
Add GetServiceState action for MoSAPI service monitoring (#2906)
* Add GetServiceState action for MoSAPI service monitoring Implements the `/api/mosapi/getServiceState` endpoint to retrieve service health summaries for TLDs from the MoSAPI system. - Introduces `GetServiceStateAction` to fetch TLD service status. - Implements `MosApiStateService` to transform raw MoSAPI responses into a curated `ServiceStateSummary`. - Uses concurrent processing with a fixed thread pool to fetch states for all configured TLDs efficiently while respecting MoSAPI rate limits. junit test added * Refactor MoSAPI models to records and address review nits - Convert model classes to Java records for conciseness and immutability. - Update unit tests to use Java text blocks for improved JSON readability. - Simplify service and action layers by removing redundant logic and logging. - Fix configuration nits regarding primitive types and comment formatting. * Consolidate MoSAPI models and enhance null-safety - Moves model records into a single MosApiModels.java file. - Switches to ImmutableList/ImmutableMap with non-null defaults in constructors. - Removes redundant pass-through methods in MosApiStateService. - Updates tests to use Java Text Blocks and non-null collection assertions. * Improve MoSAPI client error handling and clean up data models Refactors the MoSAPI monitoring client to be more robust against infrastructure failures * Refactor: use nullToEmptyImmutableCopy() for MoSAPI models Standardize null-handling in model classes by using the Nomulus `nullToEmptyImmutableCopy()` utility. This ensures consistent API responses with empty lists instead of omitted fields.
This commit is contained in:
@@ -28,6 +28,7 @@ import google.registry.flows.TlsCredentials.EppTlsModule;
|
||||
import google.registry.flows.custom.CustomLogicModule;
|
||||
import google.registry.loadtest.LoadTestModule;
|
||||
import google.registry.monitoring.whitebox.WhiteboxModule;
|
||||
import google.registry.mosapi.module.MosApiRequestModule;
|
||||
import google.registry.rdap.RdapModule;
|
||||
import google.registry.rde.RdeModule;
|
||||
import google.registry.reporting.ReportingModule;
|
||||
@@ -60,6 +61,7 @@ import google.registry.ui.server.console.ConsoleModule;
|
||||
EppToolModule.class,
|
||||
IcannReportingModule.class,
|
||||
LoadTestModule.class,
|
||||
MosApiRequestModule.class,
|
||||
RdapModule.class,
|
||||
RdeModule.class,
|
||||
ReportingModule.class,
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
// Copyright 2025 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.mosapi;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.net.MediaType;
|
||||
import com.google.gson.Gson;
|
||||
import google.registry.mosapi.MosApiModels.AllServicesStateResponse;
|
||||
import google.registry.mosapi.MosApiModels.ServiceStateSummary;
|
||||
import google.registry.request.HttpException.ServiceUnavailableException;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import java.util.Optional;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
/** Unit tests for {@link GetServiceStateAction}. */
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class GetServiceStateActionTest {
|
||||
|
||||
@Mock private MosApiStateService stateService;
|
||||
private final FakeResponse response = new FakeResponse();
|
||||
private final Gson gson = new Gson();
|
||||
|
||||
@Test
|
||||
void testRun_singleTld_returnsStateForTld() throws Exception {
|
||||
GetServiceStateAction action =
|
||||
new GetServiceStateAction(stateService, response, gson, Optional.of("example"));
|
||||
|
||||
ServiceStateSummary summary = new ServiceStateSummary("example", "Up", null);
|
||||
when(stateService.getServiceStateSummary("example")).thenReturn(summary);
|
||||
|
||||
action.run();
|
||||
|
||||
assertThat(response.getContentType()).isEqualTo(MediaType.JSON_UTF_8);
|
||||
assertThat(response.getPayload())
|
||||
.contains(
|
||||
"""
|
||||
"overallStatus":"Up"
|
||||
"""
|
||||
.trim());
|
||||
verify(stateService).getServiceStateSummary("example");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRun_noTld_returnsStateForAll() {
|
||||
GetServiceStateAction action =
|
||||
new GetServiceStateAction(stateService, response, gson, Optional.empty());
|
||||
|
||||
AllServicesStateResponse allStates = new AllServicesStateResponse(ImmutableList.of());
|
||||
when(stateService.getAllServiceStateSummaries()).thenReturn(allStates);
|
||||
|
||||
action.run();
|
||||
|
||||
assertThat(response.getContentType()).isEqualTo(MediaType.JSON_UTF_8);
|
||||
assertThat(response.getPayload())
|
||||
.contains(
|
||||
"""
|
||||
"serviceStates":[]
|
||||
"""
|
||||
.trim());
|
||||
verify(stateService).getAllServiceStateSummaries();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRun_serviceThrowsException_throwsServiceUnavailable() throws Exception {
|
||||
GetServiceStateAction action =
|
||||
new GetServiceStateAction(stateService, response, gson, Optional.of("example"));
|
||||
|
||||
doThrow(new MosApiException("Backend error", null))
|
||||
.when(stateService)
|
||||
.getServiceStateSummary("example");
|
||||
|
||||
ServiceUnavailableException thrown =
|
||||
assertThrows(ServiceUnavailableException.class, action::run);
|
||||
|
||||
assertThat(thrown).hasMessageThat().isEqualTo("Error fetching MoSAPI service state.");
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -11,7 +11,7 @@
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
package google.registry.mosapi.model;
|
||||
package google.registry.mosapi;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
@@ -20,7 +20,6 @@ import google.registry.mosapi.MosApiException.DateOrderInvalidException;
|
||||
import google.registry.mosapi.MosApiException.EndDateSyntaxInvalidException;
|
||||
import google.registry.mosapi.MosApiException.MosApiAuthorizationException;
|
||||
import google.registry.mosapi.MosApiException.StartDateSyntaxInvalidException;
|
||||
import google.registry.mosapi.model.MosApiErrorResponse;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Unit tests for {@link MosApiException}. */
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
// Copyright 2025 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.mosapi;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import google.registry.mosapi.MosApiModels.AllServicesStateResponse;
|
||||
import google.registry.mosapi.MosApiModels.IncidentSummary;
|
||||
import google.registry.mosapi.MosApiModels.ServiceStateSummary;
|
||||
import google.registry.mosapi.MosApiModels.ServiceStatus;
|
||||
import google.registry.mosapi.MosApiModels.TldServiceState;
|
||||
import org.junit.Test;
|
||||
|
||||
/** Tests for {@link MosApiModels}. */
|
||||
public final class MosApiModelsTest {
|
||||
|
||||
private static final Gson gson =
|
||||
new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
|
||||
|
||||
@Test
|
||||
public void testAllServicesStateResponse_nullCollection_initializedToEmpty() {
|
||||
AllServicesStateResponse response = new AllServicesStateResponse(null);
|
||||
assertThat(response.serviceStates()).isEmpty();
|
||||
assertThat(response.serviceStates()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServiceStateSummary_nullCollection_initializedToEmpty() {
|
||||
ServiceStateSummary summary = new ServiceStateSummary("example", "Up", null);
|
||||
assertThat(summary.activeIncidents()).isEmpty();
|
||||
assertThat(summary.activeIncidents()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServiceStatus_nullCollection_initializedToEmpty() {
|
||||
ServiceStatus status = new ServiceStatus("Up", 0.0, null);
|
||||
assertThat(status.incidents()).isEmpty();
|
||||
assertThat(status.incidents()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTldServiceState_nullCollection_initializedToEmpty() {
|
||||
TldServiceState state = new TldServiceState("example", 123456L, "Up", null);
|
||||
assertThat(state.serviceStatuses()).isEmpty();
|
||||
assertThat(state.serviceStatuses()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIncidentSummary_jsonSerialization() {
|
||||
IncidentSummary incident = new IncidentSummary("inc-123", 1000L, false, "Active", 2000L);
|
||||
String json = gson.toJson(incident);
|
||||
// Using Text Blocks to avoid escaping quotes
|
||||
assertThat(json)
|
||||
.contains(
|
||||
"""
|
||||
"incidentID":"inc-123"
|
||||
"""
|
||||
.trim());
|
||||
assertThat(json)
|
||||
.contains(
|
||||
"""
|
||||
"startTime":1000
|
||||
"""
|
||||
.trim());
|
||||
assertThat(json)
|
||||
.contains(
|
||||
"""
|
||||
"falsePositive":false
|
||||
"""
|
||||
.trim());
|
||||
assertThat(json)
|
||||
.contains(
|
||||
"""
|
||||
"state":"Active"
|
||||
"""
|
||||
.trim());
|
||||
assertThat(json)
|
||||
.contains(
|
||||
"""
|
||||
"endTime":2000
|
||||
"""
|
||||
.trim());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServiceStatus_jsonSerialization() {
|
||||
IncidentSummary incident = new IncidentSummary("inc-1", 1000L, false, "Resolved", null);
|
||||
ServiceStatus status = new ServiceStatus("Down", 75.5, ImmutableList.of(incident));
|
||||
String json = gson.toJson(status);
|
||||
assertThat(json)
|
||||
.contains(
|
||||
"""
|
||||
"status":"Down"
|
||||
"""
|
||||
.trim());
|
||||
assertThat(json)
|
||||
.contains(
|
||||
"""
|
||||
"emergencyThreshold":75.5
|
||||
"""
|
||||
.trim());
|
||||
assertThat(json)
|
||||
.contains(
|
||||
"""
|
||||
"incidents":[
|
||||
"""
|
||||
.trim());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTldServiceState_jsonSerialization() {
|
||||
ServiceStatus dnsStatus = new ServiceStatus("Up", 0.0, ImmutableList.of());
|
||||
TldServiceState state =
|
||||
new TldServiceState("app", 1700000000L, "Up", ImmutableMap.of("DNS", dnsStatus));
|
||||
|
||||
String json = gson.toJson(state);
|
||||
assertThat(json)
|
||||
.contains(
|
||||
"""
|
||||
"tld":"app"
|
||||
"""
|
||||
.trim());
|
||||
assertThat(json)
|
||||
.contains(
|
||||
"""
|
||||
"status":"Up"
|
||||
"""
|
||||
.trim());
|
||||
assertThat(json)
|
||||
.contains(
|
||||
"""
|
||||
"testedServices":{"DNS":{
|
||||
"""
|
||||
.trim());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllServicesStateResponse_jsonSerialization() {
|
||||
ServiceStateSummary summary = new ServiceStateSummary("dev", "Up", ImmutableList.of());
|
||||
AllServicesStateResponse response = new AllServicesStateResponse(ImmutableList.of(summary));
|
||||
|
||||
String json = gson.toJson(response);
|
||||
assertThat(json)
|
||||
.contains(
|
||||
"""
|
||||
"serviceStates":[
|
||||
"""
|
||||
.trim());
|
||||
assertThat(json)
|
||||
.contains(
|
||||
"""
|
||||
"tld":"dev"
|
||||
"""
|
||||
.trim());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
// Copyright 2025 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.mosapi;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
import google.registry.mosapi.MosApiModels.AllServicesStateResponse;
|
||||
import google.registry.mosapi.MosApiModels.IncidentSummary;
|
||||
import google.registry.mosapi.MosApiModels.ServiceStateSummary;
|
||||
import google.registry.mosapi.MosApiModels.ServiceStatus;
|
||||
import google.registry.mosapi.MosApiModels.TldServiceState;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
/** Unit tests for {@link MosApiStateService}. */
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class MosApiStateServiceTest {
|
||||
|
||||
@Mock private ServiceMonitoringClient client;
|
||||
|
||||
private final ExecutorService executor = MoreExecutors.newDirectExecutorService();
|
||||
|
||||
private MosApiStateService service;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
service = new MosApiStateService(client, ImmutableSet.of("tld1", "tld2"), executor);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetServiceStateSummary_upStatus_returnsEmptyIncidents() throws Exception {
|
||||
TldServiceState rawState = new TldServiceState("tld1", 12345L, "Up", ImmutableMap.of());
|
||||
when(client.getTldServiceState("tld1")).thenReturn(rawState);
|
||||
|
||||
ServiceStateSummary result = service.getServiceStateSummary("tld1");
|
||||
|
||||
assertThat(result.tld()).isEqualTo("tld1");
|
||||
assertThat(result.overallStatus()).isEqualTo("Up");
|
||||
assertThat(result.activeIncidents()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetServiceStateSummary_downStatus_filtersActiveIncidents() throws Exception {
|
||||
IncidentSummary dnsIncident = new IncidentSummary("inc-1", 100L, false, "Open", null);
|
||||
ServiceStatus dnsService = new ServiceStatus("Down", 50.0, ImmutableList.of(dnsIncident));
|
||||
|
||||
ServiceStatus rdapService = new ServiceStatus("Up", 0.0, ImmutableList.of());
|
||||
|
||||
TldServiceState rawState =
|
||||
new TldServiceState(
|
||||
"tld1", 12345L, "Down", ImmutableMap.of("DNS", dnsService, "RDAP", rdapService));
|
||||
|
||||
when(client.getTldServiceState("tld1")).thenReturn(rawState);
|
||||
|
||||
ServiceStateSummary result = service.getServiceStateSummary("tld1");
|
||||
|
||||
assertThat(result.overallStatus()).isEqualTo("Down");
|
||||
assertThat(result.activeIncidents()).hasSize(1);
|
||||
|
||||
ServiceStatus incidentSummary = result.activeIncidents().get(0);
|
||||
assertThat(incidentSummary.status()).isEqualTo("DNS");
|
||||
assertThat(incidentSummary.incidents()).containsExactly(dnsIncident);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetServiceStateSummary_throwsException_whenClientFails() throws Exception {
|
||||
when(client.getTldServiceState("tld1")).thenThrow(new MosApiException("Network error", null));
|
||||
|
||||
assertThrows(MosApiException.class, () -> service.getServiceStateSummary("tld1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAllServiceStateSummaries_success() throws Exception {
|
||||
TldServiceState state1 = new TldServiceState("tld1", 1L, "Up", ImmutableMap.of());
|
||||
TldServiceState state2 = new TldServiceState("tld2", 2L, "Up", ImmutableMap.of());
|
||||
|
||||
when(client.getTldServiceState("tld1")).thenReturn(state1);
|
||||
when(client.getTldServiceState("tld2")).thenReturn(state2);
|
||||
|
||||
AllServicesStateResponse response = service.getAllServiceStateSummaries();
|
||||
|
||||
assertThat(response.serviceStates()).hasSize(2);
|
||||
assertThat(response.serviceStates().stream().map(ServiceStateSummary::tld))
|
||||
.containsExactly("tld1", "tld2");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAllServiceStateSummaries_partialFailure_returnsErrorState() throws Exception {
|
||||
TldServiceState state1 = new TldServiceState("tld1", 1L, "Up", ImmutableMap.of());
|
||||
when(client.getTldServiceState("tld1")).thenReturn(state1);
|
||||
|
||||
when(client.getTldServiceState("tld2")).thenThrow(new MosApiException("Failure", null));
|
||||
|
||||
AllServicesStateResponse response = service.getAllServiceStateSummaries();
|
||||
|
||||
assertThat(response.serviceStates()).hasSize(2);
|
||||
|
||||
ServiceStateSummary summary1 =
|
||||
response.serviceStates().stream().filter(s -> s.tld().equals("tld1")).findFirst().get();
|
||||
assertThat(summary1.overallStatus()).isEqualTo("Up");
|
||||
|
||||
ServiceStateSummary summary2 =
|
||||
response.serviceStates().stream().filter(s -> s.tld().equals("tld2")).findFirst().get();
|
||||
|
||||
assertThat(summary2.overallStatus()).isEqualTo("ERROR");
|
||||
assertThat(summary2.activeIncidents()).isEmpty();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
// Copyright 2025 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.mosapi;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.ArgumentMatchers.anyMap;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import google.registry.mosapi.MosApiModels.TldServiceState;
|
||||
import google.registry.tools.GsonUtils;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.Protocol;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class ServiceMonitoringClientTest {
|
||||
|
||||
private static final String TLD = "example";
|
||||
private static final String ENDPOINT = "v2/monitoring/state";
|
||||
private final MosApiClient mosApiClient = mock(MosApiClient.class);
|
||||
private final Gson gson = GsonUtils.provideGson();
|
||||
private ServiceMonitoringClient client;
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
client = new ServiceMonitoringClient(mosApiClient, gson);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetTldServiceState_success() throws Exception {
|
||||
String jsonResponse =
|
||||
"""
|
||||
{
|
||||
"tld": "example",
|
||||
"services": [
|
||||
{
|
||||
"service": "DNS",
|
||||
"status": "OPERATIONAL"
|
||||
}
|
||||
]
|
||||
}
|
||||
""";
|
||||
|
||||
try (Response response = createMockResponse(200, jsonResponse)) {
|
||||
when(mosApiClient.sendGetRequest(eq(TLD), eq(ENDPOINT), anyMap(), anyMap()))
|
||||
.thenReturn(response);
|
||||
|
||||
TldServiceState result = client.getTldServiceState(TLD);
|
||||
assertThat(gson.toJson(result)).contains("example");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetTldServiceState_apiError_throwsMosApiException() throws Exception {
|
||||
String errorJson =
|
||||
"""
|
||||
{
|
||||
"resultCode": "2011",
|
||||
"message": "Invalid duration"
|
||||
}
|
||||
""";
|
||||
|
||||
try (Response response = createMockResponse(400, errorJson)) {
|
||||
when(mosApiClient.sendGetRequest(eq(TLD), eq(ENDPOINT), anyMap(), anyMap()))
|
||||
.thenReturn(response);
|
||||
|
||||
MosApiException thrown =
|
||||
assertThrows(MosApiException.class, () -> client.getTldServiceState(TLD));
|
||||
assertThat(thrown.getMessage()).contains("2011");
|
||||
assertThat(thrown.getMessage()).contains("Invalid duration");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetTldServiceState_nonJsonError_throwsMosApiException() throws Exception {
|
||||
String htmlError =
|
||||
"""
|
||||
<html>
|
||||
<body>502 Bad Gateway</body>
|
||||
</html>
|
||||
""";
|
||||
|
||||
try (Response response = createMockResponse(502, htmlError)) {
|
||||
when(mosApiClient.sendGetRequest(eq(TLD), eq(ENDPOINT), anyMap(), anyMap()))
|
||||
.thenReturn(response);
|
||||
|
||||
MosApiException thrown =
|
||||
assertThrows(MosApiException.class, () -> client.getTldServiceState(TLD));
|
||||
assertThat(thrown.getMessage()).contains("MoSAPI json parsing error (502)");
|
||||
assertThat(thrown.getMessage()).contains("502 Bad Gateway");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetTldServiceState_emptyBody_throwsMosApiException() throws Exception {
|
||||
Response response =
|
||||
new Response.Builder()
|
||||
.request(new Request.Builder().url("http://localhost").build())
|
||||
.protocol(Protocol.HTTP_1_1)
|
||||
.code(204)
|
||||
.message("No Content")
|
||||
.build();
|
||||
|
||||
when(mosApiClient.sendGetRequest(eq(TLD), eq(ENDPOINT), anyMap(), anyMap()))
|
||||
.thenReturn(response);
|
||||
|
||||
MosApiException thrown =
|
||||
assertThrows(MosApiException.class, () -> client.getTldServiceState(TLD));
|
||||
assertThat(thrown.getMessage()).contains("returned an empty body");
|
||||
}
|
||||
|
||||
private Response createMockResponse(int code, String body) {
|
||||
return new Response.Builder()
|
||||
.request(new Request.Builder().url("http://localhost").build())
|
||||
.protocol(Protocol.HTTP_1_1)
|
||||
.code(code)
|
||||
.message(code == 200 ? "OK" : "Error")
|
||||
.body(ResponseBody.create(body, MediaType.parse("application/json")))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
// Copyright 2025 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.mosapi.module;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.util.Optional;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Unit tests for {@link MosApiRequestModule}. */
|
||||
public class MosApiRequestModuleTest {
|
||||
|
||||
@Test
|
||||
void testProvideTld_paramPresent() {
|
||||
HttpServletRequest req = mock(HttpServletRequest.class);
|
||||
when(req.getParameter("tld")).thenReturn("example.tld");
|
||||
|
||||
Optional<String> result = MosApiRequestModule.provideTld(req);
|
||||
|
||||
assertThat(result).hasValue("example.tld");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testProvideTld_paramMissing() {
|
||||
HttpServletRequest req = mock(HttpServletRequest.class);
|
||||
when(req.getParameter("tld")).thenReturn(null);
|
||||
|
||||
Optional<String> result = MosApiRequestModule.provideTld(req);
|
||||
|
||||
assertThat(result).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testProvideTld_paramEmptyString() {
|
||||
HttpServletRequest req = mock(HttpServletRequest.class);
|
||||
when(req.getParameter("tld")).thenReturn("");
|
||||
|
||||
Optional<String> result = MosApiRequestModule.provideTld(req);
|
||||
|
||||
assertThat(result).isEmpty();
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ BACKEND /_dr/admin/verifyOte VerifyOteAction
|
||||
BACKEND /_dr/cron/fanout TldFanoutAction GET y APP ADMIN
|
||||
BACKEND /_dr/epptool EppToolAction POST n APP ADMIN
|
||||
BACKEND /_dr/loadtest LoadTestAction POST y APP ADMIN
|
||||
BACKEND /_dr/mosapi/getServiceState GetServiceStateAction GET n APP ADMIN
|
||||
BACKEND /_dr/task/brdaCopy BrdaCopyAction POST y APP ADMIN
|
||||
BACKEND /_dr/task/bsaDownload BsaDownloadAction GET,POST n APP ADMIN
|
||||
BACKEND /_dr/task/bsaRefresh BsaRefreshAction GET,POST n APP ADMIN
|
||||
|
||||
Reference in New Issue
Block a user