issue #9 - Refactor CfClientTest, CfDnsClient, and CfBasicHttpClient: improve error handling, enable record filtering, refine empty result behavior, and update tests for clarity and robustness.
This commit is contained in:
@@ -71,8 +71,19 @@ abstract class CfBasicHttpClient {
|
||||
T respObj = objectMapper.readValue(result.responseBody, responseType);
|
||||
if (!respObj.getResponseResultInfo().isSuccess()) {
|
||||
log.error("API error.");
|
||||
respObj.getResponseResultInfo().getErrors().forEach(e -> log.error(" - {}", e.toString()));
|
||||
throw new CloudflareApiException("API error.");
|
||||
StringBuilder errorMessage = new StringBuilder("API error");
|
||||
if (!respObj.getResponseResultInfo().getErrors().isEmpty()) {
|
||||
errorMessage.append(": ");
|
||||
respObj.getResponseResultInfo().getErrors().forEach(e -> {
|
||||
log.error(" - {}", e.toString());
|
||||
errorMessage.append(e).append("; ");
|
||||
});
|
||||
// Remove trailing "; "
|
||||
if (errorMessage.toString().endsWith("; ")) {
|
||||
errorMessage.setLength(errorMessage.length() - 2);
|
||||
}
|
||||
}
|
||||
throw new CloudflareApiException(errorMessage.toString());
|
||||
}
|
||||
logUri = request.getRequestUri();
|
||||
if (result.statusCode >= 200 && result.statusCode < 300) {
|
||||
|
||||
@@ -13,6 +13,7 @@ import codes.thischwa.cf.model.RecordType;
|
||||
import codes.thischwa.cf.model.ZoneEntity;
|
||||
import codes.thischwa.cf.model.ZoneMultipleResponse;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -51,6 +52,8 @@ public class CfDnsClient extends CfBasicHttpClient {
|
||||
|
||||
private final ResponseValidator responseValidator;
|
||||
|
||||
private final boolean emptyResultThrowsException;
|
||||
|
||||
/**
|
||||
* Constructs a new instance of {@code CfDnsClient}.
|
||||
*
|
||||
@@ -107,6 +110,7 @@ public class CfDnsClient extends CfBasicHttpClient {
|
||||
String authKey) {
|
||||
super(baseUrl, authEmail, authKey);
|
||||
this.responseValidator = new ResponseValidator(emptyResultThrowsException);
|
||||
this.emptyResultThrowsException = emptyResultThrowsException;
|
||||
}
|
||||
|
||||
private static String buildFqdn(ZoneEntity zone, String sld) {
|
||||
@@ -216,15 +220,12 @@ public class CfDnsClient extends CfBasicHttpClient {
|
||||
*/
|
||||
public List<RecordEntity> recordList(ZoneEntity zone, String sld, @Nullable RecordType... types)
|
||||
throws CloudflareApiException {
|
||||
String fqdn = buildFqdn(zone, sld);
|
||||
String endpoint = buildEndpointWithTypeFilters(CfRequest.RECORD_INFO_NAME.buildPath(zone.getId(), fqdn), types);
|
||||
RecordMultipleResponse resp = getRequest(endpoint, RecordMultipleResponse.class);
|
||||
checkResponse(resp, false);
|
||||
List<RecordEntity> recs = resp.getResult();
|
||||
recs.forEach(rec -> rec.setZoneId(zone.getId()));
|
||||
return recs;
|
||||
PagingRequest pagingRequest = PagingRequest.defaultPaging();
|
||||
List<RecordEntity> recs = recordList(zone, sld, pagingRequest);
|
||||
return filterAndSetZoneRecords(zone, types, recs);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves all record entities for a specific second-level domain (SLD) within a given DNS
|
||||
* zone using the provided paging request parameters.
|
||||
@@ -256,23 +257,11 @@ public class CfDnsClient extends CfBasicHttpClient {
|
||||
*/
|
||||
public List<RecordEntity> recordList(ZoneEntity zone, RecordType... types)
|
||||
throws CloudflareApiException {
|
||||
String endpoint = buildEndpointWithTypeFilters(CfRequest.RECORD_LIST.buildPath(zone.getId()), types);
|
||||
String endpoint = CfRequest.RECORD_LIST.buildPath(zone.getId());
|
||||
RecordMultipleResponse resp = getRequest(endpoint, RecordMultipleResponse.class);
|
||||
checkResponse(resp, false);
|
||||
return resp.getResult();
|
||||
}
|
||||
|
||||
private String buildEndpointWithTypeFilters(String baseEndpoint, @Nullable RecordType... types) {
|
||||
if (types == null || types.length == 0) {
|
||||
return baseEndpoint;
|
||||
}
|
||||
StringBuilder endpoint = new StringBuilder(baseEndpoint);
|
||||
String separator = baseEndpoint.contains("?") ? "&" : "?";
|
||||
for (RecordType type : types) {
|
||||
endpoint.append(separator).append("type=").append(type);
|
||||
separator = "&";
|
||||
}
|
||||
return endpoint.toString();
|
||||
List<RecordEntity> recs = resp.getResult();
|
||||
return filterAndSetZoneRecords(zone, types, recs);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -459,6 +448,24 @@ public class CfDnsClient extends CfBasicHttpClient {
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<RecordEntity> filterAndSetZoneRecords(ZoneEntity zone, @Nullable RecordType[] types, List<RecordEntity> recs)
|
||||
throws CloudflareNotFoundException {
|
||||
List<RecordEntity> filtered;
|
||||
if (types != null && types.length > 0) {
|
||||
filtered = recs.stream().filter(rec -> Arrays.asList(types).contains(RecordType.valueOf(rec.getType()))).collect(Collectors.toList());
|
||||
} else {
|
||||
filtered = new ArrayList<>(recs);
|
||||
}
|
||||
filtered.forEach(rec -> rec.setZoneId(zone.getId()));
|
||||
|
||||
// special exception for an empty result, normally it's done in the RecordValidator
|
||||
if (filtered.isEmpty() && emptyResultThrowsException) {
|
||||
throw new CloudflareNotFoundException("No records exist after filtering zone: " + zone.getName());
|
||||
}
|
||||
return filtered;
|
||||
}
|
||||
|
||||
|
||||
private List<RecordEntity> cleanRecordsForPostOrPut(List<RecordEntity> records) {
|
||||
List<RecordEntity> cleaned = new ArrayList<>();
|
||||
records.forEach(
|
||||
|
||||
@@ -5,6 +5,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
import static org.junit.jupiter.api.Assumptions.assumeTrue;
|
||||
|
||||
import codes.thischwa.cf.model.BatchEntry;
|
||||
@@ -47,30 +48,49 @@ public class CfClientTest {
|
||||
@Test
|
||||
void testAddHost() throws Exception {
|
||||
ZoneEntity zone = client.zoneGet(ZONE_STR);
|
||||
client.recordDeleteTypeIfExists(zone, SLD_STR, RecordType.A, RecordType.AAAA);
|
||||
RecordEntity record = RecordEntity.build(SLD_STR, RecordType.A, TTL, "127.0.0.1");
|
||||
RecordEntity createdRecord = client.recordCreate(zone, record);
|
||||
assertNotNull(createdRecord.getId());
|
||||
assertEquals(SLD_STR, createdRecord.getSld());
|
||||
assertEquals(RecordType.A.getType(), createdRecord.getType());
|
||||
assertEquals(TTL, createdRecord.getTtl());
|
||||
assertEquals("127.0.0.1", createdRecord.getContent());
|
||||
assertNotNull(createdRecord.getCreatedOn());
|
||||
|
||||
client.recordDeleteTypeIfExists(zone, SLD_STR, RecordType.A);
|
||||
assertThrows(CloudflareNotFoundException.class,
|
||||
() -> client.recordList(zone, SLD_STR, RecordType.A));
|
||||
try {
|
||||
// clean-up
|
||||
client.recordDeleteTypeIfExists(zone, SLD_STR, RecordType.A, RecordType.AAAA);
|
||||
|
||||
record = RecordEntity.build(SLD_STR + "." + ZONE_STR, RecordType.A, TTL, "127.1.0.1");
|
||||
createdRecord = client.recordCreate(zone, record);
|
||||
assertNotNull(createdRecord.getId());
|
||||
assertEquals(SLD_STR, createdRecord.getSld());
|
||||
assertEquals(RecordType.A.getType(), createdRecord.getType());
|
||||
assertEquals(TTL, createdRecord.getTtl());
|
||||
assertEquals("127.1.0.1", createdRecord.getContent());
|
||||
assertNotNull(createdRecord.getCreatedOn());
|
||||
RecordEntity record = RecordEntity.build(SLD_STR, RecordType.A, TTL, "127.0.0.1");
|
||||
RecordEntity createdRecord = client.recordCreate(zone, record);
|
||||
assertNotNull(createdRecord.getId());
|
||||
assertEquals(SLD_STR, createdRecord.getSld());
|
||||
assertEquals(RecordType.A.getType(), createdRecord.getType());
|
||||
assertEquals(TTL, createdRecord.getTtl());
|
||||
assertEquals("127.0.0.1", createdRecord.getContent());
|
||||
assertNotNull(createdRecord.getCreatedOn());
|
||||
|
||||
client.recordDeleteTypeIfExists(zone, SLD_STR, RecordType.A);
|
||||
List<RecordEntity> records = client.recordList(zone, SLD_STR, RecordType.A);
|
||||
assertEquals(1, records.size());
|
||||
RecordEntity fetchedRecord = records.get(0);
|
||||
assertEquals(createdRecord.getId(), fetchedRecord.getId());
|
||||
assertEquals(createdRecord.getContent(), fetchedRecord.getContent());
|
||||
assertEquals(createdRecord.getType(), fetchedRecord.getType());
|
||||
client.recordDelete(zone, createdRecord);
|
||||
|
||||
// test A and AAAA records for the same SLD
|
||||
RecordEntity recordA = RecordEntity.build(SLD_STR, RecordType.A, TTL, "127.0.0.2");
|
||||
RecordEntity recordAAAA = RecordEntity.build(SLD_STR, RecordType.AAAA, TTL, "2001:db8::1");
|
||||
RecordEntity createdRecordA = client.recordCreate(zone, recordA);
|
||||
RecordEntity createdRecordAAAA = client.recordCreate(zone, recordAAAA);
|
||||
assertNotNull(createdRecordA.getId());
|
||||
assertNotNull(createdRecordAAAA.getId());
|
||||
assertEquals(SLD_STR, createdRecordA.getSld());
|
||||
assertEquals(SLD_STR, createdRecordAAAA.getSld());
|
||||
assertEquals(RecordType.A.getType(), createdRecordA.getType());
|
||||
assertEquals(RecordType.AAAA.getType(), createdRecordAAAA.getType());
|
||||
|
||||
client.recordDeleteTypeIfExists(zone, SLD_STR, RecordType.A, RecordType.AAAA);
|
||||
assertThrows(CloudflareNotFoundException.class,
|
||||
() -> client.recordList(zone, SLD_STR, RecordType.A, RecordType.AAAA));
|
||||
} finally {
|
||||
// cleanup in case of failures during test
|
||||
try {
|
||||
client.recordDeleteTypeIfExists(zone, SLD_STR, RecordType.A, RecordType.AAAA);
|
||||
} catch (Exception e) { /* ignore */ }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -82,14 +102,6 @@ public class CfClientTest {
|
||||
() -> client.recordList(zList.get(0), "not-existing"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEmptyResultThrowsException() throws Exception {
|
||||
List<ZoneEntity> zList = client.zoneList();
|
||||
CfDnsClient client = new CfDnsClient(true, API_EMAIL, API_KEY);
|
||||
assertThrows(CloudflareNotFoundException.class,
|
||||
() -> client.recordList(zList.get(0), "not-existing"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDns() throws Exception {
|
||||
// starting point: already existing zone 'mein-d-ns.de'
|
||||
@@ -121,7 +133,7 @@ public class CfClientTest {
|
||||
createdRe1 =
|
||||
client.recordCreate(z, RecordEntity.build(domain, RecordType.A, TTL, "130.0.0.3"));
|
||||
assertNotNull(createdRe1.getId());
|
||||
assertEquals(randomSld+ "." + ZONE_STR, createdRe1.getName());
|
||||
assertEquals(randomSld + "." + ZONE_STR, createdRe1.getName());
|
||||
assertEquals(randomSld, createdRe1.getSld());
|
||||
assertEquals(RecordType.A.getType(), createdRe1.getType());
|
||||
assertEquals(z.getId(), createdRe1.getZoneId());
|
||||
@@ -156,7 +168,7 @@ public class CfClientTest {
|
||||
} else if (Objects.equals(re.getType(), RecordType.AAAA.getType())) {
|
||||
assertEquals("2a0a:4cc0:c0:2e4::1", re.getContent());
|
||||
} else {
|
||||
throw new IllegalStateException("Unexpected record type: " + re.getType());
|
||||
fail(String.format("Unexpected record type: %s", re.getType()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,12 +177,16 @@ public class CfClientTest {
|
||||
assertTrue(fullList.size() >= 2);
|
||||
assertTrue(fullList.stream().anyMatch(re -> re.getId().equals(createdRe1.getId())));
|
||||
assertTrue(fullList.stream().anyMatch(re -> re.getId().equals(createdRe2.getId())));
|
||||
assertTrue(
|
||||
fullList.stream().allMatch(re -> re.getType().equals(RecordType.A.getType()) || re.getType().equals(RecordType.AAAA.getType())));
|
||||
|
||||
// test recordList with types without SLD
|
||||
List<RecordEntity> aList = client.recordList(z, RecordType.A);
|
||||
assertFalse(aList.isEmpty());
|
||||
assertTrue(aList.size() >= 1);
|
||||
assertTrue(aList.stream().anyMatch(re -> re.getId().equals(createdRe1.getId())));
|
||||
assertTrue(aList.stream().noneMatch(re -> re.getId().equals(createdRe2.getId())));
|
||||
assertTrue(aList.stream().allMatch(re -> re.getType().equals(RecordType.A.getType())));
|
||||
|
||||
// test fluent api list
|
||||
List<RecordEntity> fluentList = client.zone(ZONE_STR).list(RecordType.A);
|
||||
|
||||
Reference in New Issue
Block a user