Add GitHub Actions for Maven setup, JUnit reporting, and SonarCloud analysis. Update README with SonarCloud badges, embed assets, and document breaking changes. Refactor APIs with paging support, add model class tests, and improve error messages and code quality. Fix #13 and fix #15.
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
name: Publish JUnit Report (Short Names)
|
||||
description: Normalize JUnit XML report names and publish a summary-only test report.
|
||||
inputs:
|
||||
token:
|
||||
description: GitHub token for creating the check run.
|
||||
required: true
|
||||
report-name:
|
||||
description: Name shown for the test report.
|
||||
required: false
|
||||
default: Summary of JUnit Tests
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Normalize JUnit report names
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p junit-short
|
||||
shopt -s globstar nullglob
|
||||
for f in **/target/*-reports/TEST-*.xml; do
|
||||
base="$(basename "$f")"
|
||||
short="${base#TEST-}"
|
||||
short="${short%.xml}"
|
||||
cp "$f" "junit-short/${short}"
|
||||
done
|
||||
|
||||
- name: Publish Test Report
|
||||
uses: dorny/test-reporter@v2
|
||||
with:
|
||||
token: ${{ inputs.token }}
|
||||
name: ${{ inputs.report-name }}
|
||||
path: "*"
|
||||
reporter: java-junit
|
||||
only-summary: true
|
||||
working-directory: "junit-short"
|
||||
@@ -0,0 +1,29 @@
|
||||
name: "Setup Maven with GitHub Packages"
|
||||
|
||||
description: "Sets up JDK, caches Maven dependencies, and configures GitHub Packages for Maven repositories."
|
||||
|
||||
inputs:
|
||||
java-version:
|
||||
description: "Java version to install"
|
||||
default: "17"
|
||||
required: true
|
||||
java-distribution:
|
||||
description: "Java distribution to use"
|
||||
default: "corretto"
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: ${{ inputs.java-distribution }}
|
||||
java-version: ${{ inputs.java-version }}
|
||||
|
||||
- name: Cache Maven Repository
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.m2/repository
|
||||
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-maven-
|
||||
@@ -0,0 +1,41 @@
|
||||
name: Build and Analyse
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- develop
|
||||
- feature*
|
||||
pull_request:
|
||||
types: [ opened, synchronize, reopened ]
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
|
||||
build-and-analyse:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
|
||||
|
||||
- name: Setup Java and Maven
|
||||
uses: ./.github/actions/setup-java-maven
|
||||
|
||||
- name: Build and analyze with SonarCloud
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||
CF_API_TOKEN: ${{ secrets.API_TOKEN }}
|
||||
run: |
|
||||
echo "Running SonarCloud analysis..."
|
||||
mvn -B -DtestClasspath=src/test/ verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=th-schwarz_CloudflareDNS-java
|
||||
|
||||
- name: Publish Test Report
|
||||
uses: ./.github/actions/publish-report/
|
||||
if: ${{ always() }}
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
report-name: Summary of JUnit Tests
|
||||
@@ -4,10 +4,10 @@ when:
|
||||
branch: develop
|
||||
|
||||
steps:
|
||||
- name: hello
|
||||
image: alpine
|
||||
commands:
|
||||
- echo "Hello World!"
|
||||
# - name: hello
|
||||
# image: alpine
|
||||
# commands:
|
||||
# - echo "Hello World!"
|
||||
|
||||
- name: maven verify
|
||||
image: maven:3-amazoncorretto-17-alpine
|
||||
|
||||
@@ -2,6 +2,14 @@
|
||||
|
||||
[](https://ci.codeberg.org/repos/16522)
|
||||
|
||||
[](https://sonarcloud.io/summary/new_code?id=th-schwarz_CloudflareDNS-java)
|
||||
[](https://sonarcloud.io/summary/new_code?id=th-schwarz_CloudflareDNS-java)
|
||||
[](https://sonarcloud.io/summary/new_code?id=th-schwarz_CloudflareDNS-java)
|
||||
[](https://sonarcloud.io/summary/new_code?id=th-schwarz_CloudflareDNS-java)
|
||||
[](https://sonarcloud.io/summary/new_code?id=th-schwarz_CloudflareDNS-java)
|
||||
|
||||
[](https://codeberg.org/th-schwarz/CloudflareDNS-java)
|
||||
|
||||
## Preface
|
||||
|
||||
This project provides a java client for minimalistic access to the Cloudflare API version 4, which is mainly used for
|
||||
@@ -42,6 +50,9 @@ The dependency is:
|
||||
|
||||
## Changelog
|
||||
|
||||
- 0.4.0-SNAPSHOT:
|
||||
- **Breaking Change**: renamed `client.zone().record()` to `client.zone().getRecord()`
|
||||
- Code quality improvements: Increasing test coverage
|
||||
- 0.3.0:
|
||||
- **Breaking Change**:
|
||||
- **New Fluent API**: Changed the initialization of the client(`new CfDnsClientBuilder().withApiTokenAuth("your-api-token").build()`)
|
||||
@@ -54,7 +65,7 @@ The dependency is:
|
||||
- RecordEntity getter methods renamed for clarity: `getName()` → `getSld()`
|
||||
- **New Fluent API**: Changed the initialization of the client(`new CfDnsClientBuilder().withApiTokenAuth("your-api-token").build()`) and added chainable method interface for more readable DNS operations (
|
||||
`client.zone().record()...`)
|
||||
- Code quality improvements: eliminated duplication in batch operations, improved type safety in HTTP methods,
|
||||
- Code quality improvements: removed duplication in batch operations, improved type safety in HTTP methods,
|
||||
optimized string concatenation, removed mutable setters from CfDnsClient
|
||||
- Enhanced type validation in `RecordEntity.build()` with better error messages
|
||||
- CfClient#recordList must return multiple RecordEntries
|
||||
@@ -359,7 +370,7 @@ that reduces verbosity and improves code readability.
|
||||
### Basic Usage
|
||||
|
||||
```java
|
||||
// Create a DNS record
|
||||
// Create a DNS getRecord
|
||||
client.zone("example.com")
|
||||
.record("api")
|
||||
.create(RecordType.A, "192.168.1.1",60);
|
||||
@@ -373,7 +384,7 @@ List<RecordEntity> records = client.zone("example.com")
|
||||
List<RecordEntity> zoneRecords = client.zone("example.com")
|
||||
.list(RecordType.A, RecordType.AAAA);
|
||||
|
||||
// Update a DNS record
|
||||
// Update a DNS getRecord
|
||||
RecordEntity updated = client.zone("example.com")
|
||||
.record("api", RecordType.A)
|
||||
.update("192.168.1.2");
|
||||
@@ -398,7 +409,7 @@ CfDnsClient client = new CfDnsClientBuilder()
|
||||
.withApiTokenAuth("your-api-token")
|
||||
.build();
|
||||
|
||||
// Create a new record
|
||||
// Create a new getRecord
|
||||
client.zone("example.com")
|
||||
.record("api")
|
||||
.create(RecordType.A, "192.168.100.1",60);
|
||||
@@ -409,7 +420,7 @@ List<RecordEntity> records = client.zone("example.com")
|
||||
.get();
|
||||
System.out.println("IP: "+records.get(0).getContent());
|
||||
|
||||
// Update the record
|
||||
// Update the getRecord
|
||||
client.zone("example.com")
|
||||
.record("api",RecordType.A)
|
||||
.update("192.168.100.2");
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
@@ -42,6 +42,15 @@
|
||||
<junit5.version>5.14.2</junit5.version>
|
||||
<mockito-junit5.version>5.21.0</mockito-junit5.version>
|
||||
|
||||
<!-- sonarqube -->
|
||||
<sonar.organization>th-schwarz</sonar.organization>
|
||||
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
|
||||
<sonar.sourceEncoding>${file.encoding}</sonar.sourceEncoding>
|
||||
<sonar.projectKey>th-schwarz_CloudflareDNS-java</sonar.projectKey>
|
||||
<sonar.projectName>CloudflareDNS-java</sonar.projectName>
|
||||
<sonar.branch.name>develop</sonar.branch.name>
|
||||
<sonar.test.exclusions>src/test/java/**/*</sonar.test.exclusions>
|
||||
|
||||
<lombok-maven-plugin.version>1.18.20.0</lombok-maven-plugin.version>
|
||||
</properties>
|
||||
|
||||
@@ -273,7 +282,6 @@
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
||||
@@ -33,6 +33,9 @@ abstract class CfBasicHttpClient {
|
||||
private final CfDnsClientBuilder.CfAuth auth;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
private record ResultWrapper(int statusCode, String responseBody) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Cloudflare HTTP client with the specified base URL and authentication.
|
||||
*
|
||||
@@ -97,7 +100,7 @@ abstract class CfBasicHttpClient {
|
||||
log.error("JSON parsing error for request to {}", logUri, e);
|
||||
throw new CloudflareApiException("Error processing JSON response", e);
|
||||
} catch (Exception e) {
|
||||
throw new CloudflareApiException("Server error!", e);
|
||||
throw new CloudflareApiException("Unexpected error!", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,7 +190,4 @@ abstract class CfBasicHttpClient {
|
||||
private String buildUrl(String endpoint) {
|
||||
return baseUrl + endpoint;
|
||||
}
|
||||
|
||||
private record ResultWrapper(int statusCode, String responseBody) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,14 +116,14 @@ public class CfDnsClient extends CfBasicHttpClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides fluent API access to operations on a specific zone.
|
||||
* Provides fluent API access to operations in a specific zone.
|
||||
* This method returns a ZoneOperations interface that allows chaining operations
|
||||
* on DNS records within the specified zone.
|
||||
*
|
||||
* <p>Example:
|
||||
* <pre><code>
|
||||
* client.zone("example.com")
|
||||
* .record("api")
|
||||
* .getRecord("api")
|
||||
* .create(RecordType.A, "192.168.1.1", 60);
|
||||
* </code></pre>
|
||||
*
|
||||
@@ -177,6 +177,33 @@ public class CfDnsClient extends CfBasicHttpClient {
|
||||
return response.getResult().get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a list of DNS records for a specified zone, with optional paging support.
|
||||
*
|
||||
* @param zone The zone entity containing information about the target zone.
|
||||
* @return A list of RecordEntity objects representing the DNS records of the specified zone.
|
||||
* @throws CloudflareApiException If an error occurs during the API request or response processing.
|
||||
*/
|
||||
public List<RecordEntity> recordList(ZoneEntity zone) throws CloudflareApiException {
|
||||
return recordList(zone, (PagingRequest) null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a list of DNS records for a specified zone, with optional paging support.
|
||||
*
|
||||
* @param zone The zone entity containing information about the target zone.
|
||||
* @param pagingRequest The paging request containing parameters such as page size and number.
|
||||
* @return A list of RecordEntity objects representing the DNS records of the specified zone.
|
||||
* @throws CloudflareApiException If an error occurs during the API request or response processing.
|
||||
*/
|
||||
public List<RecordEntity> recordList(ZoneEntity zone, @Nullable PagingRequest pagingRequest) throws CloudflareApiException {
|
||||
PagingRequest pr = pagingRequest == null ? PagingRequest.defaultPaging() : pagingRequest;
|
||||
String endpoint = pr.addQueryString(CfRequest.RECORD_LIST.buildPath(zone.getId()));
|
||||
RecordMultipleResponse resp = getRequest(endpoint, RecordMultipleResponse.class);
|
||||
checkResponse(resp);
|
||||
return resp.getResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves DNS records for the specified second-level domain (SLD) within a zone.
|
||||
*
|
||||
@@ -192,49 +219,31 @@ public class CfDnsClient extends CfBasicHttpClient {
|
||||
|
||||
/**
|
||||
* Retrieves DNS records for the specified second-level domain (SLD) within a zone.
|
||||
* Optionally filters by one or more DNS record types.
|
||||
* Optionally, filters by one or more DNS getRecord types.
|
||||
*
|
||||
* @param zone The zone entity containing information about the domain zone.
|
||||
* @param sld The second-level domain (SLD) for which to retrieve DNS records.
|
||||
* @param types Optional parameter specifying one or more DNS record types to filter the results.
|
||||
* @param types Optional parameter specifying one or more DNS getRecord types to filter the results.
|
||||
* @return A list of {@code RecordEntity} objects representing the DNS records for the specified domain.
|
||||
* @throws CloudflareNotFoundException if the specified SLD is not found in the zone
|
||||
* @throws CloudflareApiException if an error occurs while interacting with the Cloudflare API
|
||||
*/
|
||||
public List<RecordEntity> recordList(ZoneEntity zone, String sld, @Nullable RecordType... types)
|
||||
throws CloudflareApiException {
|
||||
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.
|
||||
*
|
||||
* @param zone The DNS zone entity for which the SLD records are to be fetched.
|
||||
* @param sld The second-level domain name for which the records are retrieved.
|
||||
* @param pagingRequest The paging request.
|
||||
* @return A list of {@code RecordEntity} associated with the desired SLD.
|
||||
* @throws CloudflareApiException If an error occurs while interacting with the Cloudflare API.
|
||||
*/
|
||||
public List<RecordEntity> recordList(ZoneEntity zone, String sld, PagingRequest pagingRequest)
|
||||
throws CloudflareApiException {
|
||||
String fqdn = buildFqdn(zone, sld);
|
||||
String endpoint =
|
||||
pagingRequest.addQueryString(CfRequest.RECORD_INFO_NAME.buildPath(zone.getId(), fqdn));
|
||||
String endpoint = CfRequest.RECORD_LIST_NAME.buildPath(zone.getId(), fqdn);
|
||||
RecordMultipleResponse resp = getRequest(endpoint, RecordMultipleResponse.class);
|
||||
checkResponse(resp);
|
||||
return resp.getResult();
|
||||
checkResponse(resp, false);
|
||||
List<RecordEntity> recs = resp.getResult();
|
||||
return filterAndSetZoneRecords(zone, types, recs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a list of all DNS records for a given zone.
|
||||
* Optionally filters by one or more DNS record types.
|
||||
* Optionally, filters by one or more DNS getRecord types.
|
||||
*
|
||||
* @param zone The zone entity containing information about the domain zone.
|
||||
* @param types Optional parameter specifying one or more DNS record types to filter the results.
|
||||
* @param types Optional parameter specifying one or more DNS getRecord types to filter the results.
|
||||
* @return A list of {@code RecordEntity} objects representing the DNS records for the specified zone.
|
||||
* @throws CloudflareApiException if an error occurs while interacting with the Cloudflare API
|
||||
*/
|
||||
@@ -248,17 +257,17 @@ public class CfDnsClient extends CfBasicHttpClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new DNS record for a given second-level domain (SLD) within the specified zone.
|
||||
* Creates a new DNS getRecord for a given second-level domain (SLD) within the specified zone.
|
||||
*
|
||||
* @param zone The ZoneEntity representing the DNS zone where the record is to be created.
|
||||
* @param sld The second-level domain (SLD) for which the DNS record is being created.
|
||||
* @param ttl The time-to-live (TTL) value for the DNS record in seconds.
|
||||
* @param type The RecordType specifying the type of the DNS record (e.g., A, AAAA, CNAME).
|
||||
* @param content The content of the DNS record (e.g., IP address for A/AAAA records, target
|
||||
* @param zone The ZoneEntity representing the DNS zone where the getRecord is to be created.
|
||||
* @param sld The second-level domain (SLD) for which the DNS getRecord is being created.
|
||||
* @param ttl The time-to-live (TTL) value for the DNS getRecord in seconds.
|
||||
* @param type The RecordType specifying the type of the DNS getRecord (e.g., A, AAAA, CNAME).
|
||||
* @param content The content of the DNS getRecord (e.g., IP address for A/AAAA records, target
|
||||
* domain for CNAME).
|
||||
* @return The created RecordEntity object containing details of the newly created DNS record.
|
||||
* @return The created RecordEntity object containing details of the newly created DNS getRecord.
|
||||
* @throws CloudflareApiException If an error occurs while communicating with the Cloudflare API
|
||||
* or creating the record.
|
||||
* or creating the getRecord.
|
||||
*/
|
||||
public RecordEntity recordCreateSld(ZoneEntity zone, String sld, int ttl, RecordType type,
|
||||
String content) throws CloudflareApiException {
|
||||
@@ -267,14 +276,14 @@ public class CfDnsClient extends CfBasicHttpClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a DNS record in the specified DNS zone with the provided details.
|
||||
* Creates a DNS getRecord in the specified DNS zone with the provided details.
|
||||
*
|
||||
* @param zone the DNS zone in which the record will be created
|
||||
* @param name the name of the DNS record (e.g., www.example.com)
|
||||
* @param ttl the time-to-live (TTL) value for the DNS record
|
||||
* @param type the type of the DNS record (e.g., A, AAAA, CNAME)
|
||||
* @param content the content or value of the DNS record
|
||||
* @return the created DNS record as a {@link RecordEntity} object
|
||||
* @param zone the DNS zone in which the getRecord will be created
|
||||
* @param name the name of the DNS getRecord (e.g., www.example.com)
|
||||
* @param ttl the time-to-live (TTL) value for the DNS getRecord
|
||||
* @param type the type of the DNS getRecord (e.g., A, AAAA, CNAME)
|
||||
* @param content the content or value of the DNS getRecord
|
||||
* @return the created DNS getRecord as a {@link RecordEntity} object
|
||||
* @throws CloudflareApiException if an error occurs while interacting with the Cloudflare API
|
||||
*/
|
||||
public RecordEntity recordCreate(ZoneEntity zone, String name, int ttl, RecordType type,
|
||||
@@ -284,13 +293,13 @@ public class CfDnsClient extends CfBasicHttpClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new DNS record in the specified zone using the Cloudflare API.
|
||||
* Creates a new DNS getRecord in the specified zone using the Cloudflare API.
|
||||
*
|
||||
* @param zone The zone entity where the record will be created. Contains details such as zone
|
||||
* @param zone The zone entity where the getRecord will be created. Contains details such as zone
|
||||
* ID.
|
||||
* @param rec The record entity representing the DNS record to be created, including its
|
||||
* @param rec The getRecord entity representing the DNS getRecord to be created, including its
|
||||
* attributes.
|
||||
* @return The created record entity as returned by the Cloudflare API.
|
||||
* @return The created getRecord entity as returned by the Cloudflare API.
|
||||
* @throws CloudflareApiException If an error occurs while interacting with the Cloudflare API.
|
||||
*/
|
||||
public RecordEntity recordCreate(ZoneEntity zone, RecordEntity rec)
|
||||
@@ -305,11 +314,11 @@ public class CfDnsClient extends CfBasicHttpClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a DNS record of the specified type within a given zone on the Cloudflare API.
|
||||
* Deletes a DNS getRecord of the specified type within a given zone on the Cloudflare API.
|
||||
*
|
||||
* @param zone The zone entity that specifies the zone in which the record exists.
|
||||
* @param rec The record entity that represents the DNS record to be deleted.
|
||||
* @return {@code true} if the DNS record was successfully deleted; {@code false} otherwise.
|
||||
* @param zone The zone entity that specifies the zone in which the getRecord exists.
|
||||
* @param rec The getRecord entity that represents the DNS getRecord to be deleted.
|
||||
* @return {@code true} if the DNS getRecord was successfully deleted; {@code false} otherwise.
|
||||
* @throws CloudflareApiException if there is an issue during the API communication, or the
|
||||
* request fails for any reason.
|
||||
*/
|
||||
@@ -324,11 +333,11 @@ public class CfDnsClient extends CfBasicHttpClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a DNS record of the specified type within a given zone on the Cloudflare API.
|
||||
* Deletes a DNS getRecord of the specified type within a given zone on the Cloudflare API.
|
||||
*
|
||||
* @param zone The zone entity that specifies the zone in which the record exists.
|
||||
* @param id The record entity that represents the DNS record to be deleted.
|
||||
* @return {@code true} if the DNS record was successfully deleted; {@code false} otherwise.
|
||||
* @param zone The zone entity that specifies the zone in which the getRecord exists.
|
||||
* @param id The getRecord entity that represents the DNS getRecord to be deleted.
|
||||
* @return {@code true} if the DNS getRecord was successfully deleted; {@code false} otherwise.
|
||||
* @throws CloudflareApiException if there is an issue during the API communication or the request
|
||||
* fails for any reason.
|
||||
*/
|
||||
@@ -341,12 +350,12 @@ public class CfDnsClient extends CfBasicHttpClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an existing DNS record in a specified Cloudflare zone.
|
||||
* Updates an existing DNS getRecord in a specified Cloudflare zone.
|
||||
*
|
||||
* @param zone the zone entity containing the ID of the target zone
|
||||
* @param rec the record entity containing the ID of the DNS record to be updated and its updated
|
||||
* @param rec the getRecord entity containing the ID of the DNS getRecord to be updated and its updated
|
||||
* data
|
||||
* @return the updated record entity as returned by the Cloudflare API
|
||||
* @return the updated getRecord entity as returned by the Cloudflare API
|
||||
* @throws CloudflareApiException if an error occurs while interacting with the Cloudflare API
|
||||
*/
|
||||
public RecordEntity recordUpdate(ZoneEntity zone, RecordEntity rec)
|
||||
@@ -362,11 +371,11 @@ public class CfDnsClient extends CfBasicHttpClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes DNS records of a specific type within a given zone if they exist. If no record of the
|
||||
* Deletes DNS records of a specific type within a given zone if they exist. If no getRecord of the
|
||||
* specified type exists, it logs this occurrence without throwing an exception.
|
||||
*
|
||||
* @param zone The DNS zone entity in which the record exists.
|
||||
* @param sld The second-level domain for which the record is being checked.
|
||||
* @param zone The DNS zone entity in which the getRecord exists.
|
||||
* @param sld The second-level domain for which the getRecord is being checked.
|
||||
* @param recordTypes The types of DNS records that should be deleted if they exist.
|
||||
* @throws CloudflareApiException If an error occurs during API communication.
|
||||
*/
|
||||
@@ -377,7 +386,7 @@ public class CfDnsClient extends CfBasicHttpClient {
|
||||
try {
|
||||
recs = recordList(zone, sld, recordTypes);
|
||||
} catch (CloudflareNotFoundException e) {
|
||||
log.trace("No record of type {} found for domain {}.", recordTypes, fqdn);
|
||||
log.trace("No getRecord of type {} found for domain {}.", recordTypes, fqdn);
|
||||
return;
|
||||
}
|
||||
for (RecordEntity rec : recs) {
|
||||
@@ -385,13 +394,13 @@ public class CfDnsClient extends CfBasicHttpClient {
|
||||
recordDelete(zone, rec);
|
||||
log.info("Record {} of type {} successful deleted.", fqdn, recordTypes);
|
||||
} catch (CloudflareApiException e) {
|
||||
log.error("Failed to delete record {} of type {} for zone {}: {}", fqdn, recordTypes, zone.getName(), e.getMessage());
|
||||
log.error("Failed to delete getRecord {} of type {} for zone {}: {}", fqdn, recordTypes, zone.getName(), e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a batch of DNS record operations (POST, PUT, PATCH, DELETE) for a specified zone.
|
||||
* Processes a batch of DNS getRecord operations (POST, PUT, PATCH, DELETE) for a specified zone.
|
||||
* This method builds and cleans the input records, sends the batch request to the Cloudflare API,
|
||||
* and returns a result containing processed batch entries.
|
||||
*
|
||||
@@ -407,7 +416,7 @@ public class CfDnsClient extends CfBasicHttpClient {
|
||||
@Nullable List<RecordEntity> patchRecords, @Nullable List<RecordEntity> deleteRecords)
|
||||
throws CloudflareApiException {
|
||||
BatchEntry batchEntry = new BatchEntry();
|
||||
// build 'clean' record entries
|
||||
// build 'clean' getRecord entries
|
||||
if (postRecords != null) {
|
||||
batchEntry.setPosts(cleanRecordsForPostOrPut(postRecords));
|
||||
}
|
||||
@@ -437,8 +446,7 @@ public class CfDnsClient extends CfBasicHttpClient {
|
||||
if (types != null && types.length > 0) {
|
||||
Set<RecordType> allowedTypes = new HashSet<>(Arrays.asList(types));
|
||||
filtered = recs.stream()
|
||||
.filter(rec -> allowedTypes.contains(RecordType.valueOf(rec.getType())))
|
||||
.collect(Collectors.toList());;
|
||||
.filter(rec -> allowedTypes.contains(RecordType.valueOf(rec.getType()))).toList();
|
||||
} else {
|
||||
filtered = new ArrayList<>(recs);
|
||||
}
|
||||
|
||||
@@ -22,19 +22,6 @@ public class CfDnsClientBuilder {
|
||||
@Nullable
|
||||
private String baseUrl;
|
||||
|
||||
/**
|
||||
* Constructs a new instance of `CfDnsClientBuilder`.
|
||||
*
|
||||
* <p>This class serves as a builder for creating and configuring instances of a CfDnsClient. It provides
|
||||
* a fluent API to set various optional configurations, such as API authentication methods and base
|
||||
* URL, before constructing the client.
|
||||
*
|
||||
* <p>By using this constructor, you can initiate the building process with default settings, which can
|
||||
* later be overridden using the provided builder methods.
|
||||
*/
|
||||
public CfDnsClientBuilder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures whether an exception should be thrown when an empty result is encountered
|
||||
* during operations performed by the `CfDnsClient`.
|
||||
|
||||
@@ -27,24 +27,23 @@ public enum CfRequest {
|
||||
*/
|
||||
RECORD_LIST("/zones/%s/dns_records"),
|
||||
/**
|
||||
* Represents the API endpoint path for creating a new DNS record within a specific DNS zone. The
|
||||
* Represents the API endpoint path for retrieving information about a DNS getRecord within a
|
||||
* specific DNS zone by its name. The endpoint path includes placeholders for the zone identifier
|
||||
* and the getRecord name, which need to be provided to construct the complete path.
|
||||
*/
|
||||
RECORD_LIST_NAME("/zones/%s/dns_records?name=%s"),
|
||||
/**
|
||||
* Represents the API endpoint path for creating a new DNS getRecord within a specific DNS zone. The
|
||||
* endpoint path includes a placeholder for the zone identifier, which needs to be provided to
|
||||
* construct the complete path.
|
||||
*/
|
||||
RECORD_CREATE("/zones/%s/dns_records"),
|
||||
/**
|
||||
* Represents the API endpoint path for retrieving information about a DNS record within a
|
||||
* specific DNS zone by its name. The endpoint path includes placeholders for the zone identifier
|
||||
* and the record name, which need to be provided to construct the complete path.
|
||||
*/
|
||||
RECORD_INFO_NAME("/zones/%s/dns_records?name=%s"),
|
||||
/**
|
||||
* Represents the API endpoint path for updating an existing DNS record within a specific DNS
|
||||
* zone. The endpoint path includes placeholders for the zone identifier and the record
|
||||
* Represents the API endpoint path for updating an existing DNS getRecord within a specific DNS
|
||||
* zone. The endpoint path includes placeholders for the zone identifier and the getRecord
|
||||
* identifier, which need to be provided to construct the complete path.
|
||||
*/
|
||||
RECORD_UPDATE("/zones/%s/dns_records/%s"),
|
||||
|
||||
/**
|
||||
* Represents the API endpoint path for performing batch operations on DNS records within a specific zone.
|
||||
* The placeholder "%s" in the path is intended to be replaced by a zone identifier.
|
||||
@@ -52,8 +51,8 @@ public enum CfRequest {
|
||||
*/
|
||||
RECORD_BATCH("/zones/%s/dns_records/batch"),
|
||||
/**
|
||||
* Represents the API endpoint path for deleting an existing DNS record within a specific DNS
|
||||
* zone. The endpoint path includes placeholders for the zone identifier and the record
|
||||
* Represents the API endpoint path for deleting an existing DNS getRecord within a specific DNS
|
||||
* zone. The endpoint path includes placeholders for the zone identifier and the getRecord
|
||||
* identifier, which need to be provided to construct the complete path.
|
||||
*/
|
||||
RECORD_DELETE("/zones/%s/dns_records/%s");
|
||||
|
||||
@@ -18,17 +18,4 @@ public class CloudflareNotFoundException extends CloudflareApiException {
|
||||
public CloudflareNotFoundException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new CloudflareNotFoundException with the specified detail message and cause.
|
||||
*
|
||||
* @param message the detail message, which provides additional context about the "not found"
|
||||
* error encountered during interaction with the Cloudflare API.
|
||||
* @param cause the cause of this exception, which is the underlying throwable that triggered this
|
||||
* exception.
|
||||
*/
|
||||
public CloudflareNotFoundException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import codes.thischwa.cf.model.RecordType;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Fluent interface for record-level operations.
|
||||
* Fluent interface for getRecord-level operations.
|
||||
* Provides a chainable API for CRUD operations on DNS records.
|
||||
*/
|
||||
public interface RecordOperations {
|
||||
@@ -20,29 +20,29 @@ public interface RecordOperations {
|
||||
List<RecordEntity> get() throws CloudflareApiException;
|
||||
|
||||
/**
|
||||
* Creates a new DNS record with the specified parameters.
|
||||
* Creates a new DNS getRecord with the specified parameters.
|
||||
*
|
||||
* @param type the DNS record type (e.g., A, AAAA, CNAME)
|
||||
* @param content the content of the DNS record (e.g., IP address)
|
||||
* @param type the DNS getRecord type (e.g., A, AAAA, CNAME)
|
||||
* @param content the content of the DNS getRecord (e.g., IP address)
|
||||
* @param ttl the time-to-live value in seconds
|
||||
* @return the created RecordEntity
|
||||
* @throws CloudflareApiException if an error occurs while creating the record
|
||||
* @throws CloudflareApiException if an error occurs while creating the getRecord
|
||||
*/
|
||||
RecordEntity create(RecordType type, String content, int ttl) throws CloudflareApiException;
|
||||
|
||||
/**
|
||||
* Updates an existing DNS record with new content.
|
||||
* Updates an existing DNS getRecord with new content.
|
||||
*
|
||||
* @param newContent the new content for the DNS record
|
||||
* @param newContent the new content for the DNS getRecord
|
||||
* @return the updated RecordEntity
|
||||
* @throws CloudflareApiException if an error occurs while updating the record
|
||||
* @throws CloudflareApiException if an error occurs while updating the getRecord
|
||||
*/
|
||||
RecordEntity update(String newContent) throws CloudflareApiException;
|
||||
|
||||
/**
|
||||
* Deletes DNS records of the specified types.
|
||||
*
|
||||
* @param types the DNS record types to delete
|
||||
* @param types the DNS getRecord types to delete
|
||||
* @throws CloudflareApiException if an error occurs while deleting records
|
||||
*/
|
||||
void delete(RecordType... types) throws CloudflareApiException;
|
||||
|
||||
@@ -9,7 +9,7 @@ import java.util.List;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Implementation of RecordOperations for fluent API access to record-level operations.
|
||||
* Implementation of RecordOperations for fluent API access to getRecord-level operations.
|
||||
*/
|
||||
public class RecordOperationsImpl implements RecordOperations {
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ public interface ZoneOperations {
|
||||
* @return a RecordOperations instance for chaining record-specific operations
|
||||
* @throws CloudflareApiException if the zone cannot be found or accessed
|
||||
*/
|
||||
RecordOperations record(String sld) throws CloudflareApiException;
|
||||
RecordOperations getRecord(String sld) throws CloudflareApiException;
|
||||
|
||||
/**
|
||||
* Selects a record with specific types within the zone for further operations.
|
||||
@@ -27,7 +27,7 @@ public interface ZoneOperations {
|
||||
* @return a RecordOperations instance for chaining record-specific operations
|
||||
* @throws CloudflareApiException if the zone cannot be found or accessed
|
||||
*/
|
||||
RecordOperations record(String sld, @Nullable RecordType... types) throws CloudflareApiException;
|
||||
RecordOperations getRecord(String sld, @Nullable RecordType... types) throws CloudflareApiException;
|
||||
|
||||
/**
|
||||
* Lists all DNS records within the zone, optionally filtered by types.
|
||||
|
||||
@@ -28,12 +28,12 @@ public class ZoneOperationsImpl implements ZoneOperations {
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecordOperations record(String sld) throws CloudflareApiException {
|
||||
public RecordOperations getRecord(String sld) throws CloudflareApiException {
|
||||
return new RecordOperationsImpl(client, zone, sld, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecordOperations record(String sld, @Nullable RecordType... types) throws CloudflareApiException {
|
||||
public RecordOperations getRecord(String sld, @Nullable RecordType... types) throws CloudflareApiException {
|
||||
return new RecordOperationsImpl(client, zone, sld, types);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,24 +6,24 @@
|
||||
*
|
||||
* <p>Example usage:
|
||||
* <pre><code>
|
||||
* // Create a DNS record
|
||||
* // Create a DNS getRecord
|
||||
* client.zone("example.com")
|
||||
* .record("api")
|
||||
* .getRecord("api")
|
||||
* .create(RecordType.A, "192.168.1.1", 60);
|
||||
*
|
||||
* // Get DNS records
|
||||
* List<RecordEntity> records = client.zone("example.com")
|
||||
* .record("www", RecordType.A)
|
||||
* .getRecord("www", RecordType.A)
|
||||
* .get();
|
||||
*
|
||||
* // Update a DNS record
|
||||
* // Update a DNS getRecord
|
||||
* client.zone("example.com")
|
||||
* .record("api", RecordType.A)
|
||||
* .getRecord("api", RecordType.A)
|
||||
* .update("192.168.1.2");
|
||||
*
|
||||
* // Delete DNS records
|
||||
* client.zone("example.com")
|
||||
* .record("old-service")
|
||||
* .getRecord("old-service")
|
||||
* .delete(RecordType.A, RecordType.AAAA);
|
||||
* </code></pre>
|
||||
*/
|
||||
|
||||
@@ -5,11 +5,11 @@ import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* Represents a batch entry containing different types of operations on record entities.
|
||||
* Represents a batch entry containing different types of operations on getRecord entities.
|
||||
*
|
||||
* <p>A BatchEntry groups together collections of operations (patches, posts, puts, and deletes)
|
||||
* intended to be performed as part of a single batch process. Each operation corresponds to a specific
|
||||
* type of action on DNS record entities.
|
||||
* type of action on DNS getRecord entities.
|
||||
*
|
||||
* <ul>
|
||||
* <li><b>patches</b>: A list of {@link RecordEntity} objects representing partial updates to existing records.
|
||||
|
||||
@@ -5,7 +5,7 @@ package codes.thischwa.cf.model;
|
||||
*
|
||||
* <p>This class is used for API responses where the primary result is a batch entry,
|
||||
* which includes collections of operations such as patches, posts, puts, and deletes
|
||||
* performed on DNS record entities.
|
||||
* performed on DNS getRecord entities.
|
||||
*
|
||||
* <p>Extends {@code AbstractSingleResponse} with {@code BatchEntry} as the generic type,
|
||||
* ensuring that the response result is a batch of operations.
|
||||
|
||||
@@ -25,7 +25,7 @@ public class PagingRequest {
|
||||
* Default page size for retrieving all records in a single request.
|
||||
* Set to a very high value to effectively disable pagination when fetching all records.
|
||||
*/
|
||||
private static final int DEFAULT_ALL_RECORDS_PAGE_SIZE = 5_000_000;
|
||||
private static final int DEFAULT_ALL_RECORDS_PAGE_SIZE = 1000;
|
||||
|
||||
private int page;
|
||||
private int perPage;
|
||||
@@ -77,7 +77,7 @@ public class PagingRequest {
|
||||
}
|
||||
|
||||
private String queryString(boolean add) {
|
||||
String qs = "page=" + page + "&perPage=" + perPage;
|
||||
String qs = "page=" + page + "&per_page=" + perPage;
|
||||
return add ? "&" + qs : "?" + qs;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,22 +6,22 @@ import lombok.EqualsAndHashCode;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Represents a DNS record entity within a specific zone.
|
||||
* Represents a DNS getRecord entity within a specific zone.
|
||||
*
|
||||
* <p>Attributes defined in this class include:
|
||||
*
|
||||
* <ul>
|
||||
* <li>DNS record type such as "A" or "CNAME".
|
||||
* <li>Name of the DNS record.
|
||||
* <li>Content of the DNS record, such as an IP address.
|
||||
* <li>Flags indicating whether the record is proxiable or proxied.
|
||||
* <li>TTL (Time-To-Live) for the DNS record.
|
||||
* <li>A locked status to indicate the immutability of the record.
|
||||
* <li>DNS getRecord type such as "A" or "CNAME".
|
||||
* <li>Name of the DNS getRecord.
|
||||
* <li>Content of the DNS getRecord, such as an IP address.
|
||||
* <li>Flags indicating whether the getRecord is proxiable or proxied.
|
||||
* <li>TTL (Time-To-Live) for the DNS getRecord.
|
||||
* <li>A locked status to indicate the immutability of the getRecord.
|
||||
* <li>Zone-specific metadata including zone ID and name.
|
||||
* <li>Timestamps for creation and modification.
|
||||
* </ul>
|
||||
*
|
||||
* <p>Provides a static factory method {@code build} for creating a DNS record with specific
|
||||
* <p>Provides a static factory method {@code build} for creating a DNS getRecord with specific
|
||||
* attributes.
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@@ -45,7 +45,7 @@ public class RecordEntity extends AbstractEntity {
|
||||
|
||||
/**
|
||||
* Initializes a new instance of the RecordEntity class and invokes the parent constructor from
|
||||
* the AbstractEntity class. The RecordEntity class represents a DNS record entity within a
|
||||
* the AbstractEntity class. The RecordEntity class represents a DNS getRecord entity within a
|
||||
* specific zone, encapsulating attributes such as type, name, content, TTL, and other related
|
||||
* metadata.
|
||||
*/
|
||||
@@ -56,10 +56,10 @@ public class RecordEntity extends AbstractEntity {
|
||||
/**
|
||||
* Builds and returns a {@link RecordEntity} instance with the specified attributes.
|
||||
*
|
||||
* @param name the name of the DNS record
|
||||
* @param type the {@link RecordType} of the DNS record
|
||||
* @param ttl the time-to-live (TTL) value for the DNS record
|
||||
* @param content the content of the DNS record, typically an IP address
|
||||
* @param name the name of the DNS getRecord
|
||||
* @param type the {@link RecordType} of the DNS getRecord
|
||||
* @param ttl the time-to-live (TTL) value for the DNS getRecord
|
||||
* @param content the content of the DNS getRecord, typically an IP address
|
||||
* @return a {@link RecordEntity} populated with the provided attributes
|
||||
*/
|
||||
public static RecordEntity build(String name, RecordType type, Integer ttl, String content) {
|
||||
@@ -74,8 +74,8 @@ public class RecordEntity extends AbstractEntity {
|
||||
/**
|
||||
* Builds and returns a {@link RecordEntity} instance with the specified ID and content.
|
||||
*
|
||||
* @param id the unique identifier for the DNS record
|
||||
* @param content the content of the DNS record, typically an IP address or other record data
|
||||
* @param id the unique identifier for the DNS getRecord
|
||||
* @param content the content of the DNS getRecord, typically an IP address or other getRecord data
|
||||
* @return a {@link RecordEntity} populated with the provided ID and content
|
||||
*/
|
||||
public static RecordEntity build(String id, String content) {
|
||||
@@ -88,11 +88,11 @@ public class RecordEntity extends AbstractEntity {
|
||||
/**
|
||||
* Builds and returns a {@link RecordEntity} instance with the specified attributes.
|
||||
*
|
||||
* @param id the unique identifier for the DNS record
|
||||
* @param name the name of the DNS record
|
||||
* @param type the type of the DNS record, represented as a string (e.g., "A", "CNAME")
|
||||
* @param ttl the time-to-live (TTL) value for the DNS record
|
||||
* @param content the content of the DNS record, typically an IP address or other record data
|
||||
* @param id the unique identifier for the DNS getRecord
|
||||
* @param name the name of the DNS getRecord
|
||||
* @param type the type of the DNS getRecord, represented as a string (e.g., "A", "CNAME")
|
||||
* @param ttl the time-to-live (TTL) value for the DNS getRecord
|
||||
* @param content the content of the DNS getRecord, typically an IP address or other getRecord data
|
||||
* @return a {@link RecordEntity} populated with the provided attributes
|
||||
* @throws IllegalArgumentException if the type string is not a valid RecordType
|
||||
*/
|
||||
@@ -101,7 +101,7 @@ public class RecordEntity extends AbstractEntity {
|
||||
try {
|
||||
recordType = RecordType.valueOf(type);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new IllegalArgumentException("Invalid record type: " + type + ". Must be one of: "
|
||||
throw new IllegalArgumentException("Invalid getRecord type: " + type + ". Must be one of: "
|
||||
+ java.util.Arrays.toString(RecordType.values()), e);
|
||||
}
|
||||
RecordEntity rec = new RecordEntity();
|
||||
@@ -114,11 +114,11 @@ public class RecordEntity extends AbstractEntity {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the short name (subdomain) of the DNS record.
|
||||
* Retrieves the short name (subdomain) of the DNS getRecord.
|
||||
* If the name contains a dot ('.'), only the substring before the first dot is returned.
|
||||
* This is useful for getting the subdomain part of a fully qualified domain name.
|
||||
*
|
||||
* @return the short name of the DNS record (substring before the first dot),
|
||||
* @return the short name of the DNS getRecord (substring before the first dot),
|
||||
* or the full name if no dot is present
|
||||
*/
|
||||
public String getSld() {
|
||||
|
||||
@@ -9,7 +9,7 @@ public class RecordMultipleResponse extends AbstractMultipleResponse<RecordEntit
|
||||
/**
|
||||
* Constructs an instance of RecordMultipleResponse.
|
||||
*
|
||||
* <p>This class represents a response containing multiple DNS record entities from the
|
||||
* <p>This class represents a response containing multiple DNS getRecord entities from the
|
||||
* Cloudflare API. It inherits functionality from AbstractMultipleResponse to handle multiple
|
||||
* records of type RecordEntity.
|
||||
*/
|
||||
|
||||
@@ -11,7 +11,7 @@ public class RecordSingleResponse extends AbstractSingleResponse<RecordEntity> {
|
||||
*
|
||||
* <p>This constructor initializes the RecordSingleResponse object by invoking the superclass
|
||||
* constructor. The RecordSingleResponse represents a specific API response structure that
|
||||
* encapsulates a single DNS record entity, providing mechanisms to interact with such data in the
|
||||
* encapsulates a single DNS getRecord entity, providing mechanisms to interact with such data in the
|
||||
* context of the Cloudflare API.
|
||||
*/
|
||||
public RecordSingleResponse() {
|
||||
|
||||
@@ -3,86 +3,86 @@ package codes.thischwa.cf.model;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Enum representing various DNS record types.
|
||||
* Enum representing various DNS getRecord types.
|
||||
*
|
||||
* <p>Each constant in this enum corresponds to a specific DNS record type, such as "A", "AAAA",
|
||||
* "CNAME", or "TXT". This enum provides a means to standardize the representation of these record
|
||||
* <p>Each constant in this enum corresponds to a specific DNS getRecord type, such as "A", "AAAA",
|
||||
* "CNAME", or "TXT". This enum provides a means to standardize the representation of these getRecord
|
||||
* types throughout the application while allowing easy retrieval of their string representation.
|
||||
*/
|
||||
@Getter
|
||||
public enum RecordType {
|
||||
/**
|
||||
* Represents the DNS A record type.
|
||||
* Represents the DNS A getRecord type.
|
||||
*
|
||||
* <p>The "A" record type is used to map a domain name to an IPv4 address.
|
||||
* <p>The "A" getRecord type is used to map a domain name to an IPv4 address.
|
||||
*/
|
||||
A("A"),
|
||||
/**
|
||||
* Represents the DNS AAAA record type.
|
||||
* Represents the DNS AAAA getRecord type.
|
||||
*
|
||||
* <p>The "AAAA" record type maps a domain name to an IPv6 address.
|
||||
* <p>The "AAAA" getRecord type maps a domain name to an IPv6 address.
|
||||
*/
|
||||
AAAA("AAAA"),
|
||||
/**
|
||||
* Represents the DNS CAA (Certificate Authority Authorization) record type.
|
||||
* Represents the DNS CAA (Certificate Authority Authorization) getRecord type.
|
||||
*
|
||||
* <p>The "CAA" record type is used to specify which certificate authorities (CAs) are allowed to
|
||||
* <p>The "CAA" getRecord type is used to specify which certificate authorities (CAs) are allowed to
|
||||
* issue SSL/TLS certificates for a domain.
|
||||
*/
|
||||
CAA("CAA"),
|
||||
/**
|
||||
* Represents the DNS CERT record type.
|
||||
* Represents the DNS CERT getRecord type.
|
||||
*
|
||||
* <p>The "CERT" record type is used to store certificates and related certificate revocation
|
||||
* <p>The "CERT" getRecord type is used to store certificates and related certificate revocation
|
||||
* lists or certificate authority data in DNS zones.
|
||||
*/
|
||||
CERT("CERT"),
|
||||
/**
|
||||
* Represents the DNS CNAME (Canonical Name) record type.
|
||||
* Represents the DNS CNAME (Canonical Name) getRecord type.
|
||||
*
|
||||
* <p>The "CNAME" record type is used to alias one domain name to another.
|
||||
* <p>The "CNAME" getRecord type is used to alias one domain name to another.
|
||||
*/
|
||||
CNAME("CNAME"),
|
||||
/**
|
||||
* Represents the DNSKEY record type.
|
||||
* Represents the DNSKEY getRecord type.
|
||||
*
|
||||
* <p>The "DNSKEY" record type is used for storing public keys in DNS, as part of the DNS Security
|
||||
* <p>The "DNSKEY" getRecord type is used for storing public keys in DNS, as part of the DNS Security
|
||||
* Extensions (DNSSEC). It helps in verifying the authenticity of DNS responses through digital
|
||||
* signatures.
|
||||
*/
|
||||
DNSKEY("DNSKEY"),
|
||||
/**
|
||||
* Represents the DNS DS (Delegation Signer) record type.
|
||||
* Represents the DNS DS (Delegation Signer) getRecord type.
|
||||
*
|
||||
* <p>The "DS" record type is used in the DNSSEC (Domain Name System Security Extensions)
|
||||
* protocol. It contains a hash of a DNSKEY record which is utilized in establishing a chain of
|
||||
* <p>The "DS" getRecord type is used in the DNSSEC (Domain Name System Security Extensions)
|
||||
* protocol. It contains a hash of a DNSKEY getRecord which is utilized in establishing a chain of
|
||||
* trust from a parent zone to a child zone.
|
||||
*/
|
||||
DS("DS"),
|
||||
/**
|
||||
* Represents the DNS HTTPS (HTTP Service) record type.
|
||||
* Represents the DNS HTTPS (HTTP Service) getRecord type.
|
||||
*
|
||||
* <p>The "HTTPS" record type is used to specify information about the HTTP/3 and related services
|
||||
* <p>The "HTTPS" getRecord type is used to specify information about the HTTP/3 and related services
|
||||
* offered by a domain.
|
||||
*/
|
||||
HTTPS("HTTPS"),
|
||||
/**
|
||||
* Represents the DNS LOC (Location) record type.
|
||||
* Represents the DNS LOC (Location) getRecord type.
|
||||
*
|
||||
* <p>The "LOC" record type is used to store geographical location information for a domain,
|
||||
* <p>The "LOC" getRecord type is used to store geographical location information for a domain,
|
||||
* including latitude, longitude, altitude, and other details. It enables associating domains with
|
||||
* physical locations.
|
||||
*/
|
||||
LOC("LOC"),
|
||||
/**
|
||||
* Represents the DNS MX (Mail Exchange) record type.
|
||||
* Represents the DNS MX (Mail Exchange) getRecord type.
|
||||
*
|
||||
* <p>The "MX" record type is used to specify the mail servers responsible for receiving email
|
||||
* <p>The "MX" getRecord type is used to specify the mail servers responsible for receiving email
|
||||
* messages on behalf of a domain.
|
||||
*/
|
||||
MX("MX"),
|
||||
/**
|
||||
* Represents the NAPTR record type for DNS configurations.
|
||||
* Represents the NAPTR getRecord type for DNS configurations.
|
||||
*
|
||||
* <p>This constant is used to specify NAPTR (Naming Authority Pointer) DNS records, which allow
|
||||
* for service discovery through flexible DNS-based mechanisms. NAPTR records are commonly used in
|
||||
@@ -99,7 +99,7 @@ public enum RecordType {
|
||||
*/
|
||||
NS("NS"),
|
||||
/**
|
||||
* Represents the "OPENPGPKEY" DNS record type.
|
||||
* Represents the "OPENPGPKEY" DNS getRecord type.
|
||||
*
|
||||
* <p>This constant is primarily used to identify DNS records of the type "OPENPGPKEY". It may be
|
||||
* utilized within the system for operations such as creating, retrieving, updating, or managing
|
||||
@@ -107,17 +107,17 @@ public enum RecordType {
|
||||
*/
|
||||
OPENPGPKEY("OPENPGPKEY"),
|
||||
/**
|
||||
* Represents a DNS record type.
|
||||
* Represents a DNS getRecord type.
|
||||
*
|
||||
* <p>The `PTR` value specifically refers to a "pointer record" in the DNS system, which is
|
||||
* <p>The `PTR` value specifically refers to a "pointer getRecord" in the DNS system, which is
|
||||
* typically used for reverse DNS lookups.
|
||||
*/
|
||||
PTR("PTR"),
|
||||
/**
|
||||
* Represents the SMIMEA DNS record type.
|
||||
* Represents the SMIMEA DNS getRecord type.
|
||||
*
|
||||
* <p>The SMIMEA resource record is used to associate a user's certificate information for email
|
||||
* message signing or encryption. This type of DNS record is part of the DNS-based Authentication
|
||||
* <p>The SMIMEA resource getRecord is used to associate a user's certificate information for email
|
||||
* message signing or encryption. This type of DNS getRecord is part of the DNS-based Authentication
|
||||
* of Named Entities (DANE) protocol.
|
||||
*
|
||||
* <p>SMIMEA records provide a mechanism for utilizing certificates in email communication
|
||||
@@ -134,41 +134,41 @@ public enum RecordType {
|
||||
*/
|
||||
SMIMEA("SMIMEA"),
|
||||
/**
|
||||
* Represents a service record (SRV) type in the DNS configuration model.
|
||||
* Represents a service getRecord (SRV) type in the DNS configuration model.
|
||||
*
|
||||
* <p>This constant may be used to identify and work with SRV record types in various DNS-related
|
||||
* <p>This constant may be used to identify and work with SRV getRecord types in various DNS-related
|
||||
* operations or integrations.
|
||||
*/
|
||||
SRV("SRV"),
|
||||
/**
|
||||
* Represents the DNS record type "SSHFP" (SSH Fingerprint), used in DNS to store cryptographic
|
||||
* Represents the DNS getRecord type "SSHFP" (SSH Fingerprint), used in DNS to store cryptographic
|
||||
* fingerprints associated with SSH host keys.
|
||||
*
|
||||
* <p>This DNS record type provides a mechanism for verifying the authenticity of an SSH server
|
||||
* <p>This DNS getRecord type provides a mechanism for verifying the authenticity of an SSH server
|
||||
* before initiating a connection, enhancing the security of SSH communications.
|
||||
*/
|
||||
SSHFP("SSHFP"),
|
||||
/**
|
||||
* Represents the Service Binding (SVCB) DNS record type.
|
||||
* Represents the Service Binding (SVCB) DNS getRecord type.
|
||||
*
|
||||
* <p>The SVCB record is a DNS resource record used to indicate alternative endpoints or specific
|
||||
* <p>The SVCB getRecord is a DNS resource getRecord used to indicate alternative endpoints or specific
|
||||
* configuration details for services. It is commonly applied in service discovery and
|
||||
* protocol-specific configurations.
|
||||
*/
|
||||
SVCB("SVCB"),
|
||||
/**
|
||||
* Represents a constant for the DNS-based Authentication of Named Entities (DANE) TLSA record
|
||||
* Represents a constant for the DNS-based Authentication of Named Entities (DANE) TLSA getRecord
|
||||
* type.
|
||||
*
|
||||
* <p>The TLSA record is used to associate a TLS server certificate or public key with the domain
|
||||
* <p>The TLSA getRecord is used to associate a TLS server certificate or public key with the domain
|
||||
* name (e.g., via DNSSEC). It enables cryptographically secured connections by attaching
|
||||
* certificate and key constraints to the specific domain.
|
||||
*/
|
||||
TLSA("TLSA"),
|
||||
/**
|
||||
* Represents the TXT DNS record type.
|
||||
* Represents the TXT DNS getRecord type.
|
||||
*
|
||||
* <p>The TXT DNS record type is commonly used to store text-based information for various
|
||||
* <p>The TXT DNS getRecord type is commonly used to store text-based information for various
|
||||
* verification and configuration purposes, such as domain ownership verification or email
|
||||
* authentication protocols (e.g., SPF, DKIM).
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
package codes.thischwa.cf;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
||||
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 codes.thischwa.cf.model.RecordEntity;
|
||||
import codes.thischwa.cf.model.RecordSingleResponse;
|
||||
import codes.thischwa.cf.model.RecordType;
|
||||
import org.apache.hc.client5.http.classic.methods.HttpGet;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Unit tests for CfBasicHttpClient using mocked HTTP components.
|
||||
* Tests HTTP client functionality without requiring actual network calls.
|
||||
*/
|
||||
class CfBasicHttpClientTest {
|
||||
|
||||
/**
|
||||
* Test implementation of CfBasicHttpClient for testing purposes.
|
||||
*/
|
||||
private static class TestCfBasicHttpClient extends CfBasicHttpClient {
|
||||
|
||||
TestCfBasicHttpClient(String baseUrl, CfDnsClientBuilder.CfAuth auth) {
|
||||
super(baseUrl, auth);
|
||||
}
|
||||
|
||||
// Expose protected methods for testing
|
||||
public <T extends codes.thischwa.cf.model.AbstractResponse> T testGetRequest(String endpoint, Class<T> responseType)
|
||||
throws CloudflareApiException {
|
||||
return getRequest(endpoint, responseType);
|
||||
}
|
||||
|
||||
public <T extends codes.thischwa.cf.model.AbstractResponse> T testPostRequest(String endpoint, Object payload, Class<T> responseType)
|
||||
throws CloudflareApiException {
|
||||
return postRequest(endpoint, payload, responseType);
|
||||
}
|
||||
|
||||
public <T extends codes.thischwa.cf.model.AbstractResponse> T testPutRequest(String endpoint, Object payload, Class<T> responseType)
|
||||
throws CloudflareApiException {
|
||||
return putRequest(endpoint, payload, responseType);
|
||||
}
|
||||
|
||||
public <T extends codes.thischwa.cf.model.AbstractResponse> T testPatchRequest(String endpoint, Object payload, Class<T> responseType)
|
||||
throws CloudflareApiException {
|
||||
return patchRequest(endpoint, payload, responseType);
|
||||
}
|
||||
|
||||
public <T extends codes.thischwa.cf.model.AbstractResponse> T testDeleteRequest(String endpoint, Class<T> responseType)
|
||||
throws CloudflareApiException {
|
||||
return deleteRequest(endpoint, responseType);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConstructor_WithApiToken() {
|
||||
CfDnsClientBuilder.ApiTokenAuth auth = new CfDnsClientBuilder.ApiTokenAuth("test-token");
|
||||
TestCfBasicHttpClient client = new TestCfBasicHttpClient("https://api.cloudflare.com", auth);
|
||||
assertNotNull(client);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConstructor_WithEmailKey() {
|
||||
CfDnsClientBuilder.EmailKeyAuth auth = new CfDnsClientBuilder.EmailKeyAuth("test@example.com", "test-key");
|
||||
TestCfBasicHttpClient client = new TestCfBasicHttpClient("https://api.cloudflare.com", auth);
|
||||
assertNotNull(client);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testApiException_unknowEndpoint() {
|
||||
CfDnsClientBuilder.ApiTokenAuth auth = new CfDnsClientBuilder.ApiTokenAuth("test-token");
|
||||
TestCfBasicHttpClient client = new TestCfBasicHttpClient("https://api.cloudflare.com", auth);
|
||||
|
||||
// Invalid JSON will cause a parsing error
|
||||
CloudflareApiException exception = assertThrows(CloudflareApiException.class, () -> {
|
||||
client.testGetRequest("/invalid-endpoint", RecordSingleResponse.class);
|
||||
});
|
||||
|
||||
assertNotNull(exception);
|
||||
assertTrue(exception.getMessage().contains("Unexpected error"));
|
||||
Throwable cause = exception.getCause();
|
||||
assertInstanceOf(CloudflareApiException.class, cause);
|
||||
assertTrue(cause.getMessage().contains("No route for that URI"), "Expected error message: No route for that URI, but it was: " + cause.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testResultWrapper() throws Exception {
|
||||
// Test the private ResultWrapper record indirectly through client behavior
|
||||
CfDnsClientBuilder.ApiTokenAuth auth = new CfDnsClientBuilder.ApiTokenAuth("test-token");
|
||||
TestCfBasicHttpClient client = new TestCfBasicHttpClient("https://api.cloudflare.com", auth);
|
||||
|
||||
// Any request will create and use a ResultWrapper internally
|
||||
assertThrows(CloudflareApiException.class, () -> {
|
||||
client.testGetRequest("/test", RecordSingleResponse.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAuthApplicationHeader_ApiToken() {
|
||||
CfDnsClientBuilder.ApiTokenAuth auth = new CfDnsClientBuilder.ApiTokenAuth("my-token");
|
||||
HttpGet request = new HttpGet("https://api.cloudflare.com/test");
|
||||
|
||||
auth.applyAuth(request);
|
||||
|
||||
assertTrue(request.containsHeader("Authorization"));
|
||||
assertEquals("Bearer my-token", request.getFirstHeader("Authorization").getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAuthApplicationHeader_EmailKey() {
|
||||
CfDnsClientBuilder.EmailKeyAuth auth = new CfDnsClientBuilder.EmailKeyAuth("test@example.com", "my-key");
|
||||
HttpGet request = new HttpGet("https://api.cloudflare.com/test");
|
||||
|
||||
auth.applyAuth(request);
|
||||
|
||||
assertTrue(request.containsHeader("X-Auth-Email"));
|
||||
assertTrue(request.containsHeader("X-Auth-Key"));
|
||||
assertEquals("test@example.com", request.getFirstHeader("X-Auth-Email").getValue());
|
||||
assertEquals("my-key", request.getFirstHeader("X-Auth-Key").getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBaseUrlConstruction() {
|
||||
CfDnsClientBuilder.ApiTokenAuth auth = new CfDnsClientBuilder.ApiTokenAuth("test-token");
|
||||
|
||||
// Test default base URL
|
||||
TestCfBasicHttpClient client = new TestCfBasicHttpClient("https://api.cloudflare.com", auth);
|
||||
assertNotNull(client);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testObjectMapperInitialization() {
|
||||
// ObjectMapper is initialized in constructor via JsonConf
|
||||
CfDnsClientBuilder.ApiTokenAuth auth = new CfDnsClientBuilder.ApiTokenAuth("test-token");
|
||||
TestCfBasicHttpClient client = new TestCfBasicHttpClient("https://api.cloudflare.com", auth);
|
||||
|
||||
// If ObjectMapper wasn't initialized, any request would fail with NullPointerException
|
||||
assertThrows(CloudflareApiException.class, () -> {
|
||||
client.testGetRequest("/test", RecordSingleResponse.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRequestPayloadSerialization() {
|
||||
CfDnsClientBuilder.ApiTokenAuth auth = new CfDnsClientBuilder.ApiTokenAuth("test-token");
|
||||
TestCfBasicHttpClient client = new TestCfBasicHttpClient("https://api.cloudflare.com", auth);
|
||||
|
||||
RecordEntity record = RecordEntity.build("test.example.com", RecordType.A, 300, "1.2.3.4");
|
||||
|
||||
// The payload serialization happens inside postRequest
|
||||
assertThrows(CloudflareApiException.class, () -> {
|
||||
client.testPostRequest("/test", record, RecordSingleResponse.class);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -66,7 +66,7 @@ public class CfClientPenTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Invalid record content and TTL boundaries must be rejected by API")
|
||||
@DisplayName("Invalid getRecord content and TTL boundaries must be rejected by API")
|
||||
void testInvalidRecordCreateInputsRejected() throws Exception {
|
||||
CfDnsClient client = newClient();
|
||||
ZoneEntity zone = client.zoneGet(ZONE_STR);
|
||||
@@ -81,11 +81,11 @@ public class CfClientPenTest {
|
||||
}
|
||||
|
||||
try {
|
||||
// A record with invalid IPv4
|
||||
// A getRecord with invalid IPv4
|
||||
assertThrows(CloudflareApiException.class,
|
||||
() -> client.recordCreate(zone, fqdn, 60, RecordType.A, "999.999.999.999"));
|
||||
|
||||
// AAAA record with non-IP content
|
||||
// AAAA getRecord with non-IP content
|
||||
assertThrows(CloudflareApiException.class,
|
||||
() -> client.recordCreate(zone, fqdn, 60, RecordType.AAAA, "not-an-ipv6"));
|
||||
|
||||
|
||||
@@ -9,14 +9,18 @@ import static org.junit.jupiter.api.Assertions.fail;
|
||||
import static org.junit.jupiter.api.Assumptions.assumeTrue;
|
||||
|
||||
import codes.thischwa.cf.model.BatchEntry;
|
||||
import codes.thischwa.cf.model.PagingRequest;
|
||||
import codes.thischwa.cf.model.RecordEntity;
|
||||
import codes.thischwa.cf.model.RecordType;
|
||||
import codes.thischwa.cf.model.ZoneEntity;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -91,6 +95,19 @@ public class CfClientTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testZoneList() throws CloudflareApiException {
|
||||
List<ZoneEntity> zones = client.zoneList();
|
||||
assertNotNull(zones);
|
||||
assertFalse(zones.isEmpty());
|
||||
assertEquals(ZONE_STR, zones.get(0).getName());
|
||||
|
||||
zones = client.zoneList(PagingRequest.of(1, 100));
|
||||
assertNotNull(zones);
|
||||
assertFalse(zones.isEmpty());
|
||||
assertEquals(ZONE_STR, zones.get(0).getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testZoneListAnlFailedSldList() throws Exception {
|
||||
List<ZoneEntity> zList = client.zoneList();
|
||||
@@ -127,7 +144,7 @@ public class CfClientTest {
|
||||
// ensure clean state
|
||||
client.recordDeleteTypeIfExists(z, randomSld, RecordType.A, RecordType.AAAA);
|
||||
|
||||
// create A record using recordCreate with full domain
|
||||
// create A getRecord using recordCreate with full domain
|
||||
createdRe1 =
|
||||
client.recordCreate(z, RecordEntity.build(domain, RecordType.A, TTL, "130.0.0.3"));
|
||||
assertNotNull(createdRe1.getId());
|
||||
@@ -146,7 +163,7 @@ public class CfClientTest {
|
||||
r = aRecords.get(0);
|
||||
assertEquals("130.0.0.3", r.getContent());
|
||||
|
||||
// create AAAA record using recordCreateSld
|
||||
// create AAAA getRecord using recordCreateSld
|
||||
createdRe2 =
|
||||
client.recordCreateSld(z, randomSld, TTL, RecordType.AAAA, "2a0a:4cc0:c0:2e4::1");
|
||||
List<RecordEntity> aaaaRecords = client.recordList(z, randomSld, RecordType.AAAA);
|
||||
@@ -166,7 +183,7 @@ public class CfClientTest {
|
||||
} else if (Objects.equals(re.getType(), RecordType.AAAA.getType())) {
|
||||
assertEquals("2a0a:4cc0:c0:2e4::1", re.getContent());
|
||||
} else {
|
||||
fail(String.format("Unexpected record type: %s", re.getType()));
|
||||
fail(String.format("Unexpected getRecord type: %s", re.getType()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,7 +198,6 @@ public class CfClientTest {
|
||||
// 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())));
|
||||
@@ -191,7 +207,7 @@ public class CfClientTest {
|
||||
assertFalse(fluentList.isEmpty());
|
||||
assertTrue(fluentList.stream().anyMatch(re -> re.getId().equals(createdRe1.getId())));
|
||||
|
||||
// update AAAA record
|
||||
// update AAAA getRecord
|
||||
createdRe2.setContent("2a0a:4cc0:c0:2e4::2");
|
||||
client.recordUpdate(z, createdRe2);
|
||||
aaaaRecords = client.recordList(z, randomSld, RecordType.AAAA);
|
||||
@@ -199,18 +215,18 @@ public class CfClientTest {
|
||||
r = aaaaRecords.get(0);
|
||||
assertEquals("2a0a:4cc0:c0:2e4::2", r.getContent());
|
||||
|
||||
// verify A record still intact
|
||||
// verify A getRecord still intact
|
||||
aRecords = client.recordList(z, randomSld, RecordType.A);
|
||||
assertEquals(1, aRecords.size());
|
||||
r = aRecords.get(0);
|
||||
assertEquals("130.0.0.3", r.getContent());
|
||||
|
||||
// delete AAAA record and verify it's gone
|
||||
// delete AAAA getRecord and verify it's gone
|
||||
assertTrue(client.recordDelete(z, createdRe2));
|
||||
assertThrows(CloudflareNotFoundException.class,
|
||||
() -> client.recordList(z, randomSld, RecordType.AAAA));
|
||||
|
||||
// delete A record using helper and verify it's gone
|
||||
// delete A getRecord using helper and verify it's gone
|
||||
client.recordDeleteTypeIfExists(z, randomSld, RecordType.A);
|
||||
assertThrows(CloudflareNotFoundException.class,
|
||||
() -> client.recordList(z, randomSld, RecordType.A));
|
||||
@@ -226,7 +242,7 @@ public class CfClientTest {
|
||||
void testRecordEntityInvalidType() {
|
||||
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
|
||||
() -> RecordEntity.build("id123", "example.com", "INVALID_TYPE", 60, "192.168.1.1"));
|
||||
assertTrue(exception.getMessage().contains("Invalid record type: INVALID_TYPE"));
|
||||
assertTrue(exception.getMessage().contains("Invalid getRecord type: INVALID_TYPE"));
|
||||
assertTrue(exception.getMessage().contains("Must be one of:"));
|
||||
}
|
||||
|
||||
@@ -373,7 +389,7 @@ public class CfClientTest {
|
||||
try {
|
||||
// Test fluent create
|
||||
RecordEntity created = client.zone(ZONE_STR)
|
||||
.record(fluentSld)
|
||||
.getRecord(fluentSld)
|
||||
.create(RecordType.A, "192.168.100.1", TTL);
|
||||
|
||||
assertNotNull(created.getId());
|
||||
@@ -382,7 +398,7 @@ public class CfClientTest {
|
||||
|
||||
// Test fluent get
|
||||
List<RecordEntity> records = client.zone(ZONE_STR)
|
||||
.record(fluentSld, RecordType.A)
|
||||
.getRecord(fluentSld, RecordType.A)
|
||||
.get();
|
||||
|
||||
assertEquals(1, records.size());
|
||||
@@ -390,18 +406,18 @@ public class CfClientTest {
|
||||
|
||||
// Test fluent update
|
||||
RecordEntity updated = client.zone(ZONE_STR)
|
||||
.record(fluentSld, RecordType.A)
|
||||
.getRecord(fluentSld, RecordType.A)
|
||||
.update("192.168.100.2");
|
||||
|
||||
assertEquals("192.168.100.2", updated.getContent());
|
||||
|
||||
// Test fluent delete
|
||||
client.zone(ZONE_STR)
|
||||
.record(fluentSld)
|
||||
.getRecord(fluentSld)
|
||||
.delete(RecordType.A);
|
||||
|
||||
assertThrows(CloudflareNotFoundException.class,
|
||||
() -> client.zone(ZONE_STR).record(fluentSld, RecordType.A).get());
|
||||
() -> client.zone(ZONE_STR).getRecord(fluentSld, RecordType.A).get());
|
||||
|
||||
} finally {
|
||||
try {
|
||||
@@ -425,7 +441,7 @@ public class CfClientTest {
|
||||
assertNotNull(groupedRecords, "Resulting map should not be null.");
|
||||
assertEquals(2, groupedRecords.size(), "The grouping should result in 2 FQDN keys.");
|
||||
assertEquals(2, groupedRecords.get("example.com.").size(), "The key 'example.com.' should have 2 records.");
|
||||
assertEquals(1, groupedRecords.get("sub.example.com.").size(), "The key 'sub.example.com.' should have 1 record.");
|
||||
assertEquals(1, groupedRecords.get("sub.example.com.").size(), "The key 'sub.example.com.' should have 1 getRecord.");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -445,4 +461,68 @@ public class CfClientTest {
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testPaging() throws Exception {
|
||||
ZoneEntity zone = client.zoneGet(ZONE_STR);
|
||||
String pagingSld = "paging-" + System.currentTimeMillis();
|
||||
|
||||
try {
|
||||
int existingCount = 0;
|
||||
try {
|
||||
List<RecordEntity> allRecords = client.recordList(zone);
|
||||
existingCount = allRecords.size();
|
||||
} catch (CloudflareApiException e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
// Calculate how many records we need to create to reach at least 12 total A records
|
||||
// (to test paging with pageSize 5: page 1 = 5, page 2 = 5, page 3 = 2+)
|
||||
int targetCount = 12;
|
||||
int recordsToCreate = Math.max(0, targetCount - existingCount);
|
||||
|
||||
// Create additional A records if needed
|
||||
List<RecordEntity> createdRecords = new ArrayList<>();
|
||||
for (int i = 1; i <= recordsToCreate; i++) {
|
||||
RecordEntity record = RecordEntity.build(pagingSld, RecordType.A, TTL, "127.0.0." + i);
|
||||
RecordEntity created = client.recordCreate(zone, record);
|
||||
createdRecords.add(created);
|
||||
assertNotNull(created.getId());
|
||||
}
|
||||
|
||||
// Test paging with page size of 5
|
||||
PagingRequest page1Request = PagingRequest.of(1, 5);
|
||||
List<RecordEntity> page1Records = client.recordList(zone, page1Request);
|
||||
assertEquals(5, page1Records.size(), "First page should contain 5 records");
|
||||
|
||||
// 2nd page should also contain 5 records (if we have at least 12 total)
|
||||
PagingRequest page2Request = PagingRequest.of(2, 5);
|
||||
List<RecordEntity> page2Records = client.recordList(zone, page2Request);
|
||||
assertEquals(5, page2Records.size(), "Second page should contain at least 5 records");
|
||||
|
||||
// 3rd page should contain 2 records
|
||||
PagingRequest page3Request = PagingRequest.of(3, 5);
|
||||
List<RecordEntity> page3Records = client.recordList(zone, page3Request);
|
||||
assertEquals(2, page3Records.size(), "Third page should contain 2 records");
|
||||
|
||||
// Verify no overlap between pages
|
||||
List<String> page1Ids = page1Records.stream().map(RecordEntity::getId).toList();
|
||||
List<String> page2Ids = page2Records.stream().map(RecordEntity::getId).toList();
|
||||
List<String> page3Ids = page3Records.stream().map(RecordEntity::getId).toList();
|
||||
Set<String> generatedRecordIds = new HashSet<>(page1Ids);
|
||||
generatedRecordIds.addAll(page2Ids);
|
||||
generatedRecordIds.addAll(page3Ids);
|
||||
assertEquals(createdRecords.size(), generatedRecordIds.size());
|
||||
|
||||
// Verify our created records are in the zone
|
||||
List<RecordEntity> allRecords = client.recordList(zone);
|
||||
Set<String> allRecordIds = allRecords.stream().map(RecordEntity::getId).collect(Collectors.toSet());
|
||||
assertEquals(createdRecords.size(), allRecordIds.size());
|
||||
assertTrue(allRecordIds.containsAll(generatedRecordIds));
|
||||
} finally {
|
||||
try {
|
||||
client.recordDeleteTypeIfExists(zone, pagingSld, RecordType.A);
|
||||
} catch (Exception e) { /* ignore */ }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
package codes.thischwa.cf;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Unit tests for CfDnsClientBuilder and its authentication classes.
|
||||
*/
|
||||
class CfDnsClientBuilderTest {
|
||||
|
||||
@Test
|
||||
void testBuildWithApiToken() {
|
||||
CfDnsClient client = new CfDnsClientBuilder()
|
||||
.withApiTokenAuth("test-token")
|
||||
.build();
|
||||
|
||||
assertNotNull(client);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBuildWithEmailKey() {
|
||||
CfDnsClient client = new CfDnsClientBuilder()
|
||||
.withEmailKeyAuth("test@example.com", "test-key")
|
||||
.build();
|
||||
|
||||
assertNotNull(client);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBuildWithCustomBaseUrl() {
|
||||
CfDnsClient client = new CfDnsClientBuilder()
|
||||
.withApiTokenAuth("test-token")
|
||||
.withBaseUrl("https://custom-api.example.com")
|
||||
.build();
|
||||
|
||||
assertNotNull(client);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBuildWithDefaultBaseUrl() {
|
||||
CfDnsClient client = new CfDnsClientBuilder()
|
||||
.withApiTokenAuth("test-token")
|
||||
.build();
|
||||
|
||||
assertNotNull(client);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBuildWithEmptyResultThrowsException() {
|
||||
CfDnsClient client = new CfDnsClientBuilder()
|
||||
.withApiTokenAuth("test-token")
|
||||
.withEmptyResultThrowsException(true)
|
||||
.build();
|
||||
|
||||
assertNotNull(client);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBuildWithEmptyResultDoesNotThrowException() {
|
||||
CfDnsClient client = new CfDnsClientBuilder()
|
||||
.withApiTokenAuth("test-token")
|
||||
.withEmptyResultThrowsException(false)
|
||||
.build();
|
||||
|
||||
assertNotNull(client);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBuilderMethodChaining() {
|
||||
CfDnsClient client = new CfDnsClientBuilder()
|
||||
.withApiTokenAuth("test-token")
|
||||
.withBaseUrl("https://custom-api.example.com")
|
||||
.withEmptyResultThrowsException(true)
|
||||
.build();
|
||||
|
||||
assertNotNull(client);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testApiTokenAuth_BlankToken() {
|
||||
assertThrows(IllegalArgumentException.class, () -> new CfDnsClientBuilder.ApiTokenAuth(" "));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEmailKeyAuth_ValidCredentials() {
|
||||
CfDnsClientBuilder.EmailKeyAuth auth = new CfDnsClientBuilder.EmailKeyAuth(
|
||||
"test@example.com",
|
||||
"valid-key"
|
||||
);
|
||||
assertNotNull(auth);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEmailKeyAuth_BlankEmail() {
|
||||
assertThrows(IllegalArgumentException.class, () -> new CfDnsClientBuilder.EmailKeyAuth(" ", "valid-key"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEmailKeyAuth_BlankKey() {
|
||||
assertThrows(IllegalArgumentException.class, () -> new CfDnsClientBuilder.EmailKeyAuth("test@example.com", " "));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEmailKeyAuth_BothBlank() {
|
||||
assertThrows(IllegalArgumentException.class, () -> new CfDnsClientBuilder.EmailKeyAuth(" ", " "));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDefaultBaseUrl() {
|
||||
assertEquals("https://api.cloudflare.com/client/v4", CfDnsClientBuilder.DEFAULT_BASEURL);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBuilderWithMultipleConfigurations() {
|
||||
// Test switching auth methods in the same builder (last one wins)
|
||||
CfDnsClient client = new CfDnsClientBuilder()
|
||||
.withEmailKeyAuth("test@example.com", "old-key")
|
||||
.withApiTokenAuth("new-token") // This should override the email/key auth
|
||||
.build();
|
||||
|
||||
assertNotNull(client);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBuilderWithMultipleBaseUrls() {
|
||||
// Test setting base URL multiple times (last one wins)
|
||||
CfDnsClient client = new CfDnsClientBuilder()
|
||||
.withApiTokenAuth("test-token")
|
||||
.withBaseUrl("https://old-api.example.com")
|
||||
.withBaseUrl("https://new-api.example.com") // This should override
|
||||
.build();
|
||||
|
||||
assertNotNull(client);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEmptyResultThrowsExceptionToggle() {
|
||||
// Test toggling the flag multiple times (last one wins)
|
||||
CfDnsClient client = new CfDnsClientBuilder()
|
||||
.withApiTokenAuth("test-token")
|
||||
.withEmptyResultThrowsException(true)
|
||||
.withEmptyResultThrowsException(false) // This should override
|
||||
.build();
|
||||
|
||||
assertNotNull(client);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,399 @@
|
||||
package codes.thischwa.cf;
|
||||
|
||||
import codes.thischwa.cf.fluent.ZoneOperations;
|
||||
import codes.thischwa.cf.model.*;
|
||||
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;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
* Unit tests for CfDnsClient using mocked HTTP client responses.
|
||||
* Tests all public methods without requiring actual Cloudflare API access.
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class CfDnsClientMockTest {
|
||||
|
||||
private CfDnsClient client;
|
||||
|
||||
@Mock
|
||||
private CfBasicHttpClient mockHttpClient;
|
||||
|
||||
private static final String TEST_ZONE_ID = "zone123";
|
||||
private static final String TEST_ZONE_NAME = "example.com";
|
||||
private static final String TEST_RECORD_ID = "rec123";
|
||||
|
||||
private ZoneEntity createTestZone() {
|
||||
ZoneEntity zone = new ZoneEntity();
|
||||
zone.setId(TEST_ZONE_ID);
|
||||
zone.setName(TEST_ZONE_NAME);
|
||||
return zone;
|
||||
}
|
||||
|
||||
private ResponseResultInfo createSuccessResultInfo() {
|
||||
ResponseResultInfo resultInfo = new ResponseResultInfo();
|
||||
resultInfo.setSuccess(true);
|
||||
return resultInfo;
|
||||
}
|
||||
|
||||
private BatchResponse createBatchResponse() throws Exception {
|
||||
// Use reflection to access package-private constructor
|
||||
java.lang.reflect.Constructor<BatchResponse> constructor = BatchResponse.class.getDeclaredConstructor();
|
||||
constructor.setAccessible(true);
|
||||
return constructor.newInstance();
|
||||
}
|
||||
|
||||
private ResultInfo createResultInfo(int count) {
|
||||
return new ResultInfo(count);
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void setUp() throws Exception {
|
||||
// Create a real client with API token auth
|
||||
client = new CfDnsClientBuilder()
|
||||
.withApiTokenAuth("test-token")
|
||||
.build();
|
||||
|
||||
// Replace the internal HTTP client with our mock using reflection
|
||||
// Note: This is a workaround since CfBasicHttpClient methods are package-private
|
||||
Field responseValidatorField = CfDnsClient.class.getDeclaredField("responseValidator");
|
||||
responseValidatorField.setAccessible(true);
|
||||
responseValidatorField.set(client, new ResponseValidator(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGroupRecordsByFqdn() {
|
||||
RecordEntity rec1 = RecordEntity.build("test.example.com", RecordType.A, 300, "1.2.3.4");
|
||||
RecordEntity rec2 = RecordEntity.build("test.example.com", RecordType.AAAA, 300, "::1");
|
||||
RecordEntity rec3 = RecordEntity.build("www.example.com", RecordType.A, 300, "1.2.3.5");
|
||||
|
||||
List<RecordEntity> records = List.of(rec1, rec2, rec3);
|
||||
Map<String, List<RecordEntity>> grouped = CfDnsClient.groupRecordsByFqdn(records);
|
||||
|
||||
assertEquals(2, grouped.size());
|
||||
assertEquals(2, grouped.get("test.example.com").size());
|
||||
assertEquals(1, grouped.get("www.example.com").size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGroupRecordsByFqdn_NullInput() {
|
||||
Map<String, List<RecordEntity>> grouped = CfDnsClient.groupRecordsByFqdn(null);
|
||||
assertNotNull(grouped);
|
||||
assertTrue(grouped.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testZoneList() throws Exception {
|
||||
// Create mock zone response
|
||||
ZoneMultipleResponse mockResponse = new ZoneMultipleResponse();
|
||||
ZoneEntity zone1 = new ZoneEntity();
|
||||
zone1.setId("zone1");
|
||||
zone1.setName("example.com");
|
||||
ZoneEntity zone2 = new ZoneEntity();
|
||||
zone2.setId("zone2");
|
||||
zone2.setName("test.com");
|
||||
mockResponse.setResult(List.of(zone1, zone2));
|
||||
ResponseResultInfo resultInfo = new ResponseResultInfo();
|
||||
resultInfo.setSuccess(true);
|
||||
mockResponse.setResponseResultInfo(resultInfo);
|
||||
|
||||
// Mock the HTTP client via spy
|
||||
CfDnsClient spyClient = spy(client);
|
||||
doReturn(mockResponse).when(spyClient).getRequest(anyString(), eq(ZoneMultipleResponse.class));
|
||||
|
||||
List<ZoneEntity> zones = spyClient.zoneList();
|
||||
|
||||
assertNotNull(zones);
|
||||
assertEquals(2, zones.size());
|
||||
assertEquals("example.com", zones.get(0).getName());
|
||||
assertEquals("test.com", zones.get(1).getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testZoneGet() throws Exception {
|
||||
// Create mock zone response
|
||||
ZoneMultipleResponse mockResponse = new ZoneMultipleResponse();
|
||||
ZoneEntity zone = new ZoneEntity();
|
||||
zone.setId(TEST_ZONE_ID);
|
||||
zone.setName(TEST_ZONE_NAME);
|
||||
mockResponse.setResult(List.of(zone));
|
||||
ResponseResultInfo resultInfo = new ResponseResultInfo();
|
||||
resultInfo.setSuccess(true);
|
||||
mockResponse.setResponseResultInfo(resultInfo);
|
||||
|
||||
CfDnsClient spyClient = spy(client);
|
||||
doReturn(mockResponse).when(spyClient).getRequest(anyString(), eq(ZoneMultipleResponse.class));
|
||||
|
||||
ZoneEntity result = spyClient.zoneGet(TEST_ZONE_NAME);
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals(TEST_ZONE_ID, result.getId());
|
||||
assertEquals(TEST_ZONE_NAME, result.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testZoneOperations() throws Exception {
|
||||
// Create mock zone response
|
||||
ZoneMultipleResponse mockResponse = new ZoneMultipleResponse();
|
||||
ZoneEntity zone = new ZoneEntity();
|
||||
zone.setId(TEST_ZONE_ID);
|
||||
zone.setName(TEST_ZONE_NAME);
|
||||
mockResponse.setResult(List.of(zone));
|
||||
ResponseResultInfo resultInfo = new ResponseResultInfo();
|
||||
resultInfo.setSuccess(true);
|
||||
mockResponse.setResponseResultInfo(resultInfo);
|
||||
|
||||
CfDnsClient spyClient = spy(client);
|
||||
doReturn(mockResponse).when(spyClient).getRequest(anyString(), eq(ZoneMultipleResponse.class));
|
||||
|
||||
ZoneOperations ops = spyClient.zone(TEST_ZONE_NAME);
|
||||
|
||||
assertNotNull(ops);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRecordList_Zone() throws Exception {
|
||||
ZoneEntity zone = new ZoneEntity();
|
||||
zone.setId(TEST_ZONE_ID);
|
||||
zone.setName(TEST_ZONE_NAME);
|
||||
|
||||
RecordMultipleResponse mockResponse = new RecordMultipleResponse();
|
||||
mockResponse.setResultInfo(createResultInfo(1));
|
||||
RecordEntity rec1 = RecordEntity.build("test.example.com", RecordType.A, 300, "1.2.3.4");
|
||||
RecordEntity rec2 = RecordEntity.build("www.example.com", RecordType.A, 300, "1.2.3.5");
|
||||
mockResponse.setResult(List.of(rec1, rec2));
|
||||
ResponseResultInfo resultInfo = new ResponseResultInfo();
|
||||
resultInfo.setSuccess(true);
|
||||
mockResponse.setResponseResultInfo(resultInfo);
|
||||
|
||||
CfDnsClient spyClient = spy(client);
|
||||
doReturn(mockResponse).when(spyClient).getRequest(anyString(), eq(RecordMultipleResponse.class));
|
||||
|
||||
List<RecordEntity> records = spyClient.recordList(zone);
|
||||
|
||||
assertNotNull(records);
|
||||
assertEquals(2, records.size());
|
||||
assertEquals("1.2.3.4", records.get(0).getContent());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRecordList_WithPaging() throws Exception {
|
||||
ZoneEntity zone = createTestZone();
|
||||
PagingRequest pagingRequest = PagingRequest.of(10, 1);
|
||||
|
||||
RecordMultipleResponse mockResponse = new RecordMultipleResponse();
|
||||
mockResponse.setResultInfo(createResultInfo(1));
|
||||
RecordEntity rec1 = RecordEntity.build("test.example.com", RecordType.A, 300, "1.2.3.4");
|
||||
mockResponse.setResult(List.of(rec1));
|
||||
mockResponse.setResponseResultInfo(createSuccessResultInfo());
|
||||
|
||||
CfDnsClient spyClient = spy(client);
|
||||
doReturn(mockResponse).when(spyClient).getRequest(anyString(), eq(RecordMultipleResponse.class));
|
||||
|
||||
List<RecordEntity> records = spyClient.recordList(zone, pagingRequest);
|
||||
|
||||
assertNotNull(records);
|
||||
assertEquals(1, records.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRecordList_BySld() throws Exception {
|
||||
ZoneEntity zone = createTestZone();
|
||||
|
||||
RecordMultipleResponse mockResponse = new RecordMultipleResponse();
|
||||
mockResponse.setResultInfo(createResultInfo(1));
|
||||
RecordEntity rec1 = RecordEntity.build("test.example.com", RecordType.A, 300, "1.2.3.4");
|
||||
mockResponse.setResult(List.of(rec1));
|
||||
mockResponse.setResponseResultInfo(createSuccessResultInfo());
|
||||
|
||||
CfDnsClient spyClient = spy(client);
|
||||
doReturn(mockResponse).when(spyClient).getRequest(anyString(), eq(RecordMultipleResponse.class));
|
||||
|
||||
List<RecordEntity> records = spyClient.recordList(zone, "test");
|
||||
|
||||
assertNotNull(records);
|
||||
assertEquals(1, records.size());
|
||||
assertEquals(TEST_ZONE_ID, records.get(0).getZoneId());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRecordList_BySldAndType() throws Exception {
|
||||
ZoneEntity zone = createTestZone();
|
||||
|
||||
RecordMultipleResponse mockResponse = new RecordMultipleResponse();
|
||||
mockResponse.setResultInfo(createResultInfo(1));
|
||||
RecordEntity rec1 = RecordEntity.build("test.example.com", RecordType.A, 300, "1.2.3.4");
|
||||
RecordEntity rec2 = RecordEntity.build("test.example.com", RecordType.AAAA, 300, "::1");
|
||||
mockResponse.setResult(List.of(rec1, rec2));
|
||||
mockResponse.setResponseResultInfo(createSuccessResultInfo());
|
||||
|
||||
CfDnsClient spyClient = spy(client);
|
||||
doReturn(mockResponse).when(spyClient).getRequest(anyString(), eq(RecordMultipleResponse.class));
|
||||
|
||||
List<RecordEntity> records = spyClient.recordList(zone, "test", RecordType.A);
|
||||
|
||||
assertNotNull(records);
|
||||
assertEquals(1, records.size());
|
||||
assertEquals(RecordType.A, RecordType.valueOf(records.get(0).getType()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRecordList_ByType() throws Exception {
|
||||
ZoneEntity zone = createTestZone();
|
||||
|
||||
RecordMultipleResponse mockResponse = new RecordMultipleResponse();
|
||||
mockResponse.setResultInfo(createResultInfo(1));
|
||||
RecordEntity rec1 = RecordEntity.build("test.example.com", RecordType.A, 300, "1.2.3.4");
|
||||
RecordEntity rec2 = RecordEntity.build("www.example.com", RecordType.AAAA, 300, "::1");
|
||||
mockResponse.setResult(List.of(rec1, rec2));
|
||||
mockResponse.setResponseResultInfo(createSuccessResultInfo());
|
||||
|
||||
CfDnsClient spyClient = spy(client);
|
||||
doReturn(mockResponse).when(spyClient).getRequest(anyString(), eq(RecordMultipleResponse.class));
|
||||
|
||||
List<RecordEntity> records = spyClient.recordList(zone, RecordType.A);
|
||||
|
||||
assertNotNull(records);
|
||||
assertEquals(1, records.size());
|
||||
assertEquals(RecordType.A, RecordType.valueOf(records.get(0).getType()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRecordCreateSld() throws Exception {
|
||||
ZoneEntity zone = createTestZone();
|
||||
|
||||
RecordSingleResponse mockResponse = new RecordSingleResponse();
|
||||
RecordEntity createdRecord = RecordEntity.build("test.example.com", RecordType.A, 300, "1.2.3.4");
|
||||
createdRecord.setId(TEST_RECORD_ID);
|
||||
mockResponse.setResult(createdRecord);
|
||||
mockResponse.setResponseResultInfo(createSuccessResultInfo());
|
||||
|
||||
CfDnsClient spyClient = spy(client);
|
||||
doReturn(mockResponse).when(spyClient).postRequest(anyString(), any(), eq(RecordSingleResponse.class));
|
||||
|
||||
RecordEntity result = spyClient.recordCreate(zone, "test.example.com", 300, RecordType.A, "1.2.3.4");
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals(TEST_RECORD_ID, result.getId());
|
||||
assertEquals(TEST_ZONE_ID, result.getZoneId());
|
||||
assertEquals("1.2.3.4", result.getContent());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRecordDelete() throws Exception {
|
||||
ZoneEntity zone = createTestZone();
|
||||
|
||||
RecordSingleResponse mockResponse = new RecordSingleResponse();
|
||||
RecordEntity deletedRecord = RecordEntity.build("test.example.com", RecordType.A, 300, "1.2.3.4");
|
||||
deletedRecord.setId(TEST_RECORD_ID);
|
||||
mockResponse.setResult(deletedRecord);
|
||||
mockResponse.setResponseResultInfo(createSuccessResultInfo());
|
||||
|
||||
CfDnsClient spyClient = spy(client);
|
||||
doReturn(mockResponse).when(spyClient).deleteRequest(anyString(), eq(RecordSingleResponse.class));
|
||||
|
||||
boolean result = spyClient.recordDelete(zone, TEST_RECORD_ID);
|
||||
|
||||
assertTrue(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRecordUpdate() throws Exception {
|
||||
ZoneEntity zone = createTestZone();
|
||||
RecordEntity record = RecordEntity.build("test.example.com", RecordType.A, 300, "1.2.3.4");
|
||||
record.setId(TEST_RECORD_ID);
|
||||
|
||||
RecordSingleResponse mockResponse = new RecordSingleResponse();
|
||||
RecordEntity updatedRecord = RecordEntity.build("test.example.com", RecordType.A, 300, "1.2.3.5");
|
||||
updatedRecord.setId(TEST_RECORD_ID);
|
||||
mockResponse.setResult(updatedRecord);
|
||||
mockResponse.setResponseResultInfo(createSuccessResultInfo());
|
||||
|
||||
CfDnsClient spyClient = spy(client);
|
||||
doReturn(mockResponse).when(spyClient).patchRequest(anyString(), any(), eq(RecordSingleResponse.class));
|
||||
|
||||
RecordEntity result = spyClient.recordUpdate(zone, record);
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals(TEST_RECORD_ID, result.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRecordDeleteTypeIfExists() throws Exception {
|
||||
ZoneEntity zone = createTestZone();
|
||||
|
||||
RecordMultipleResponse listResponse = new RecordMultipleResponse();
|
||||
listResponse.setResultInfo(createResultInfo(1));
|
||||
RecordEntity rec1 = RecordEntity.build("test.example.com", RecordType.A, 300, "1.2.3.4");
|
||||
rec1.setId(TEST_RECORD_ID);
|
||||
listResponse.setResult(List.of(rec1));
|
||||
listResponse.setResponseResultInfo(createSuccessResultInfo());
|
||||
|
||||
RecordSingleResponse deleteResponse = new RecordSingleResponse();
|
||||
RecordEntity deletedRecord = RecordEntity.build("test.example.com", RecordType.A, 300, "1.2.3.4");
|
||||
deletedRecord.setId(TEST_RECORD_ID);
|
||||
deleteResponse.setResult(deletedRecord);
|
||||
deleteResponse.setResponseResultInfo(createSuccessResultInfo());
|
||||
|
||||
CfDnsClient spyClient = spy(client);
|
||||
doReturn(listResponse).when(spyClient).getRequest(anyString(), eq(RecordMultipleResponse.class));
|
||||
doReturn(deleteResponse).when(spyClient).deleteRequest(anyString(), eq(RecordSingleResponse.class));
|
||||
|
||||
// Should not throw exception
|
||||
spyClient.recordDeleteTypeIfExists(zone, "test", RecordType.A);
|
||||
|
||||
verify(spyClient, times(1)).getRequest(anyString(), eq(RecordMultipleResponse.class));
|
||||
verify(spyClient, times(1)).deleteRequest(anyString(), eq(RecordSingleResponse.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRecordDeleteTypeIfExists_NotFound() throws Exception {
|
||||
ZoneEntity zone = createTestZone();
|
||||
|
||||
CfDnsClient spyClient = spy(client);
|
||||
doThrow(new CloudflareNotFoundException("Not found")).when(spyClient).recordList(any(), anyString(), any());
|
||||
|
||||
// Should not throw exception when record doesn't exist
|
||||
assertDoesNotThrow(() -> spyClient.recordDeleteTypeIfExists(zone, "test", RecordType.A));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRecordBatch() throws Exception {
|
||||
ZoneEntity zone = createTestZone();
|
||||
|
||||
RecordEntity postRecord = RecordEntity.build("new.example.com", RecordType.A, 300, "1.2.3.4");
|
||||
RecordEntity patchRecord = RecordEntity.build(TEST_RECORD_ID, "1.2.3.5");
|
||||
RecordEntity deleteRecord = RecordEntity.build("old.example.com", RecordType.A, 300, "1.2.3.6");
|
||||
deleteRecord.setId("rec999");
|
||||
|
||||
BatchResponse mockResponse = createBatchResponse();
|
||||
BatchEntry resultEntry = new BatchEntry();
|
||||
resultEntry.setPosts(List.of(postRecord));
|
||||
resultEntry.setPatches(List.of(patchRecord));
|
||||
mockResponse.setResult(resultEntry);
|
||||
mockResponse.setResponseResultInfo(createSuccessResultInfo());
|
||||
|
||||
CfDnsClient spyClient = spy(client);
|
||||
doReturn(mockResponse).when(spyClient).postRequest(anyString(), any(), eq(BatchResponse.class));
|
||||
|
||||
BatchEntry result = spyClient.recordBatch(zone,
|
||||
List.of(postRecord),
|
||||
null,
|
||||
List.of(patchRecord),
|
||||
List.of(deleteRecord));
|
||||
|
||||
assertNotNull(result);
|
||||
assertNotNull(result.getPosts());
|
||||
assertEquals(1, result.getPosts().size());
|
||||
assertEquals(TEST_ZONE_ID, result.getPosts().get(0).getZoneId());
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,7 @@ public class CfRequestTest {
|
||||
|
||||
@Test
|
||||
public void testBuildRecordInfoName() {
|
||||
String result = CfRequest.RECORD_INFO_NAME.buildPath("zone123", "sub.domain.com");
|
||||
String result = CfRequest.RECORD_LIST_NAME.buildPath("zone123", "sub.domain.com");
|
||||
assertEquals("/zones/zone123/dns_records?name=sub.domain.com", result);
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ public class CfRequestTest {
|
||||
|
||||
@Test
|
||||
public void testBuildRecordInfo() {
|
||||
String result = CfRequest.RECORD_INFO_NAME.buildPath("zone123", "sld.domain.com");
|
||||
String result = CfRequest.RECORD_LIST_NAME.buildPath("zone123", "sld.domain.com");
|
||||
assertEquals("/zones/zone123/dns_records?name=sld.domain.com", result);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,248 @@
|
||||
package codes.thischwa.cf.fluent;
|
||||
|
||||
import codes.thischwa.cf.CfDnsClient;
|
||||
import codes.thischwa.cf.CloudflareApiException;
|
||||
import codes.thischwa.cf.model.*;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
* Unit tests for the Fluent API package (ZoneOperations and RecordOperations).
|
||||
*/
|
||||
class FluentApiTest {
|
||||
|
||||
private CfDnsClient mockClient;
|
||||
private ZoneEntity testZone;
|
||||
|
||||
private static final String TEST_ZONE_ID = "zone123";
|
||||
private static final String TEST_ZONE_NAME = "example.com";
|
||||
private static final String TEST_SLD = "test";
|
||||
private static final String TEST_RECORD_ID = "rec123";
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
mockClient = mock(CfDnsClient.class);
|
||||
testZone = new ZoneEntity();
|
||||
testZone.setId(TEST_ZONE_ID);
|
||||
testZone.setName(TEST_ZONE_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testZoneOperations_GetRecord() throws CloudflareApiException {
|
||||
ZoneOperations zoneOps = new ZoneOperationsImpl(mockClient, testZone);
|
||||
|
||||
RecordOperations recordOps = zoneOps.getRecord(TEST_SLD);
|
||||
|
||||
assertNotNull(recordOps);
|
||||
assertInstanceOf(RecordOperationsImpl.class, recordOps);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testZoneOperations_GetRecordWithTypes() throws CloudflareApiException {
|
||||
ZoneOperations zoneOps = new ZoneOperationsImpl(mockClient, testZone);
|
||||
|
||||
RecordOperations recordOps = zoneOps.getRecord(TEST_SLD, RecordType.A, RecordType.AAAA);
|
||||
|
||||
assertNotNull(recordOps);
|
||||
assertInstanceOf(RecordOperationsImpl.class, recordOps);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testZoneOperations_List() throws CloudflareApiException {
|
||||
RecordEntity rec1 = RecordEntity.build("test.example.com", RecordType.A, 300, "1.2.3.4");
|
||||
RecordEntity rec2 = RecordEntity.build("www.example.com", RecordType.A, 300, "1.2.3.5");
|
||||
List<RecordEntity> expectedRecords = List.of(rec1, rec2);
|
||||
|
||||
when(mockClient.recordList(eq(testZone), any(RecordType[].class)))
|
||||
.thenReturn(expectedRecords);
|
||||
|
||||
ZoneOperations zoneOps = new ZoneOperationsImpl(mockClient, testZone);
|
||||
List<RecordEntity> result = zoneOps.list();
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals(2, result.size());
|
||||
verify(mockClient, times(1)).recordList(eq(testZone), any(RecordType[].class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testZoneOperations_ListWithTypes() throws CloudflareApiException {
|
||||
RecordEntity rec1 = RecordEntity.build("test.example.com", RecordType.A, 300, "1.2.3.4");
|
||||
List<RecordEntity> expectedRecords = List.of(rec1);
|
||||
|
||||
when(mockClient.recordList(eq(testZone), any(RecordType[].class)))
|
||||
.thenReturn(expectedRecords);
|
||||
|
||||
ZoneOperations zoneOps = new ZoneOperationsImpl(mockClient, testZone);
|
||||
List<RecordEntity> result = zoneOps.list(RecordType.A);
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals(1, result.size());
|
||||
verify(mockClient, times(1)).recordList(eq(testZone), any(RecordType[].class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRecordOperations_Get() throws CloudflareApiException {
|
||||
RecordEntity rec1 = RecordEntity.build("test.example.com", RecordType.A, 300, "1.2.3.4");
|
||||
List<RecordEntity> expectedRecords = List.of(rec1);
|
||||
|
||||
when(mockClient.recordList(eq(testZone), eq(TEST_SLD), any()))
|
||||
.thenReturn(expectedRecords);
|
||||
|
||||
RecordOperations recordOps = new RecordOperationsImpl(mockClient, testZone, TEST_SLD, null);
|
||||
List<RecordEntity> result = recordOps.get();
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals(1, result.size());
|
||||
assertEquals("1.2.3.4", result.get(0).getContent());
|
||||
verify(mockClient, times(1)).recordList(eq(testZone), eq(TEST_SLD), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRecordOperations_GetWithTypes() throws CloudflareApiException {
|
||||
RecordEntity rec1 = RecordEntity.build("test.example.com", RecordType.A, 300, "1.2.3.4");
|
||||
List<RecordEntity> expectedRecords = List.of(rec1);
|
||||
|
||||
RecordType[] types = {RecordType.A};
|
||||
when(mockClient.recordList(eq(testZone), eq(TEST_SLD), eq(types)))
|
||||
.thenReturn(expectedRecords);
|
||||
|
||||
RecordOperations recordOps = new RecordOperationsImpl(mockClient, testZone, TEST_SLD, types);
|
||||
List<RecordEntity> result = recordOps.get();
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals(1, result.size());
|
||||
verify(mockClient, times(1)).recordList(eq(testZone), eq(TEST_SLD), eq(types));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRecordOperations_Create() throws CloudflareApiException {
|
||||
RecordEntity createdRecord = RecordEntity.build("test.example.com", RecordType.A, 300, "1.2.3.4");
|
||||
createdRecord.setId(TEST_RECORD_ID);
|
||||
|
||||
when(mockClient.recordCreateSld(eq(testZone), eq(TEST_SLD), eq(300), eq(RecordType.A), eq("1.2.3.4")))
|
||||
.thenReturn(createdRecord);
|
||||
|
||||
RecordOperations recordOps = new RecordOperationsImpl(mockClient, testZone, TEST_SLD, null);
|
||||
RecordEntity result = recordOps.create(RecordType.A, "1.2.3.4", 300);
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals(TEST_RECORD_ID, result.getId());
|
||||
assertEquals("1.2.3.4", result.getContent());
|
||||
verify(mockClient, times(1)).recordCreateSld(eq(testZone), eq(TEST_SLD), eq(300), eq(RecordType.A), eq("1.2.3.4"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRecordOperations_Update_Success() throws CloudflareApiException {
|
||||
RecordEntity existingRecord = RecordEntity.build("test.example.com", RecordType.A, 300, "1.2.3.4");
|
||||
existingRecord.setId(TEST_RECORD_ID);
|
||||
|
||||
RecordEntity updatedRecord = RecordEntity.build("test.example.com", RecordType.A, 300, "1.2.3.5");
|
||||
updatedRecord.setId(TEST_RECORD_ID);
|
||||
|
||||
when(mockClient.recordList(eq(testZone), eq(TEST_SLD), any()))
|
||||
.thenReturn(List.of(existingRecord));
|
||||
when(mockClient.recordUpdate(eq(testZone), any(RecordEntity.class)))
|
||||
.thenReturn(updatedRecord);
|
||||
|
||||
RecordOperations recordOps = new RecordOperationsImpl(mockClient, testZone, TEST_SLD, null);
|
||||
RecordEntity result = recordOps.update("1.2.3.5");
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals("1.2.3.5", result.getContent());
|
||||
verify(mockClient, times(1)).recordList(eq(testZone), eq(TEST_SLD), any());
|
||||
verify(mockClient, times(1)).recordUpdate(eq(testZone), any(RecordEntity.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRecordOperations_Update_NoRecordsFound() throws CloudflareApiException {
|
||||
when(mockClient.recordList(eq(testZone), eq(TEST_SLD), any()))
|
||||
.thenReturn(List.of());
|
||||
|
||||
RecordOperations recordOps = new RecordOperationsImpl(mockClient, testZone, TEST_SLD, null);
|
||||
|
||||
CloudflareApiException exception = assertThrows(CloudflareApiException.class, () -> {
|
||||
recordOps.update("1.2.3.5");
|
||||
});
|
||||
|
||||
assertTrue(exception.getMessage().contains("No recs found"));
|
||||
verify(mockClient, times(1)).recordList(eq(testZone), eq(TEST_SLD), any());
|
||||
verify(mockClient, never()).recordUpdate(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRecordOperations_Update_MultipleRecordsFound() throws CloudflareApiException {
|
||||
RecordEntity rec1 = RecordEntity.build("test.example.com", RecordType.A, 300, "1.2.3.4");
|
||||
RecordEntity rec2 = RecordEntity.build("test.example.com", RecordType.AAAA, 300, "::1");
|
||||
|
||||
when(mockClient.recordList(eq(testZone), eq(TEST_SLD), any()))
|
||||
.thenReturn(List.of(rec1, rec2));
|
||||
|
||||
RecordOperations recordOps = new RecordOperationsImpl(mockClient, testZone, TEST_SLD, null);
|
||||
|
||||
CloudflareApiException exception = assertThrows(CloudflareApiException.class, () -> {
|
||||
recordOps.update("1.2.3.5");
|
||||
});
|
||||
|
||||
assertTrue(exception.getMessage().contains("Multiple recs found"));
|
||||
verify(mockClient, times(1)).recordList(eq(testZone), eq(TEST_SLD), any());
|
||||
verify(mockClient, never()).recordUpdate(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRecordOperations_Delete() throws CloudflareApiException {
|
||||
doNothing().when(mockClient).recordDeleteTypeIfExists(eq(testZone), eq(TEST_SLD), any(RecordType[].class));
|
||||
|
||||
RecordOperations recordOps = new RecordOperationsImpl(mockClient, testZone, TEST_SLD, null);
|
||||
recordOps.delete(RecordType.A, RecordType.AAAA);
|
||||
|
||||
verify(mockClient, times(1)).recordDeleteTypeIfExists(eq(testZone), eq(TEST_SLD), any(RecordType[].class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRecordOperations_DeleteSingleType() throws CloudflareApiException {
|
||||
doNothing().when(mockClient).recordDeleteTypeIfExists(eq(testZone), eq(TEST_SLD), any(RecordType[].class));
|
||||
|
||||
RecordOperations recordOps = new RecordOperationsImpl(mockClient, testZone, TEST_SLD, null);
|
||||
recordOps.delete(RecordType.A);
|
||||
|
||||
verify(mockClient, times(1)).recordDeleteTypeIfExists(eq(testZone), eq(TEST_SLD), any(RecordType[].class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFluentApiChaining() throws CloudflareApiException {
|
||||
// Test that fluent API chaining works correctly
|
||||
RecordEntity createdRecord = RecordEntity.build("test.example.com", RecordType.A, 300, "1.2.3.4");
|
||||
createdRecord.setId(TEST_RECORD_ID);
|
||||
|
||||
when(mockClient.recordCreateSld(eq(testZone), eq(TEST_SLD), eq(300), eq(RecordType.A), eq("1.2.3.4")))
|
||||
.thenReturn(createdRecord);
|
||||
|
||||
ZoneOperations zoneOps = new ZoneOperationsImpl(mockClient, testZone);
|
||||
RecordEntity result = zoneOps.getRecord(TEST_SLD).create(RecordType.A, "1.2.3.4", 300);
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals(TEST_RECORD_ID, result.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConstructorFields() {
|
||||
// Test that constructor properly initializes fields
|
||||
RecordType[] types = {RecordType.A, RecordType.AAAA};
|
||||
RecordOperationsImpl recordOps = new RecordOperationsImpl(mockClient, testZone, TEST_SLD, types);
|
||||
|
||||
assertNotNull(recordOps);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testZoneOperationsImplConstructor() {
|
||||
ZoneOperationsImpl zoneOps = new ZoneOperationsImpl(mockClient, testZone);
|
||||
|
||||
assertNotNull(zoneOps);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package codes.thischwa.cf.model;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class BatchEntryTest {
|
||||
|
||||
@Test
|
||||
void testBatchEntry() {
|
||||
BatchEntry entry = new BatchEntry();
|
||||
assertEquals("", entry.getId());
|
||||
|
||||
List<RecordEntity> patches = new ArrayList<>();
|
||||
List<RecordEntity> posts = new ArrayList<>();
|
||||
List<RecordEntity> puts = new ArrayList<>();
|
||||
List<RecordEntity> deletes = new ArrayList<>();
|
||||
|
||||
entry.setPatches(patches);
|
||||
entry.setPosts(posts);
|
||||
entry.setPuts(puts);
|
||||
entry.setDeletes(deletes);
|
||||
|
||||
assertSame(patches, entry.getPatches());
|
||||
assertSame(posts, entry.getPosts());
|
||||
assertSame(puts, entry.getPuts());
|
||||
assertSame(deletes, entry.getDeletes());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLombokMethods() {
|
||||
BatchEntry entry1 = new BatchEntry();
|
||||
BatchEntry entry2 = new BatchEntry();
|
||||
assertEquals(entry1, entry2);
|
||||
assertEquals(entry1.hashCode(), entry2.hashCode());
|
||||
|
||||
List<RecordEntity> patches = List.of(new RecordEntity());
|
||||
entry1.setPatches(patches);
|
||||
assertNotEquals(entry1, entry2);
|
||||
|
||||
entry2.setPatches(patches);
|
||||
assertEquals(entry1, entry2);
|
||||
|
||||
assertTrue(entry1.toString().contains("patches="));
|
||||
}
|
||||
}
|
||||
@@ -7,15 +7,37 @@ import static org.junit.jupiter.api.Assertions.*;
|
||||
public class PagingRequestTest {
|
||||
|
||||
@Test
|
||||
public void testBuildPath() {
|
||||
void testBuildPath() {
|
||||
String result = PagingRequest.defaultPaging().addQueryString("/zones");
|
||||
assertEquals("/zones?page=1&perPage=5000000", result);
|
||||
assertEquals("/zones?page=1&per_page=1000", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuildPathAdditional() {
|
||||
void testBuildPathAdditional() {
|
||||
String result = new PagingRequest( 10, 100).addQueryString("/zones?foo=bar");
|
||||
assertEquals("/zones?foo=bar&page=10&perPage=100", result);
|
||||
assertEquals("/zones?foo=bar&page=10&per_page=100", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetPagingParams() {
|
||||
PagingRequest request = PagingRequest.of(2, 50);
|
||||
java.util.Map<String, String> params = request.getPagingParams();
|
||||
assertEquals("2", params.get("page"));
|
||||
assertEquals("50", params.get("perPage"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLombokMethods() {
|
||||
PagingRequest req1 = PagingRequest.of(1, 10);
|
||||
PagingRequest req2 = PagingRequest.of(1, 10);
|
||||
assertEquals(req1, req2);
|
||||
assertEquals(req1.hashCode(), req2.hashCode());
|
||||
assertTrue(req1.toString().contains("page=1"));
|
||||
|
||||
req1.setPage(5);
|
||||
assertEquals(5, req1.getPage());
|
||||
req1.setPerPage(20);
|
||||
assertEquals(20, req1.getPerPage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
package codes.thischwa.cf.model;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class RecordEntityTest {
|
||||
|
||||
@Test
|
||||
void testBuildWithAttributes() {
|
||||
RecordEntity rec = RecordEntity.build("example.com", RecordType.A, 120, "1.2.3.4");
|
||||
assertEquals("example.com", rec.getName());
|
||||
assertEquals("A", rec.getType());
|
||||
assertEquals(120, rec.getTtl());
|
||||
assertEquals("1.2.3.4", rec.getContent());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBuildWithIdAndContent() {
|
||||
RecordEntity rec = RecordEntity.build("id-123", "1.2.3.4");
|
||||
assertEquals("id-123", rec.getId());
|
||||
assertEquals("1.2.3.4", rec.getContent());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBuildWithIdAndAttributes() {
|
||||
RecordEntity rec = RecordEntity.build("id-123", "example.com", "A", 120, "1.2.3.4");
|
||||
assertEquals("id-123", rec.getId());
|
||||
assertEquals("example.com", rec.getName());
|
||||
assertEquals("A", rec.getType());
|
||||
assertEquals(120, rec.getTtl());
|
||||
assertEquals("1.2.3.4", rec.getContent());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBuildWithInvalidType() {
|
||||
assertThrows(IllegalArgumentException.class, () ->
|
||||
RecordEntity.build("id-123", "example.com", "INVALID", 120, "1.2.3.4")
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetSld() {
|
||||
RecordEntity rec = new RecordEntity();
|
||||
assertNull(rec.getSld());
|
||||
|
||||
rec.setName("sub.example.com");
|
||||
assertEquals("sub", rec.getSld());
|
||||
|
||||
rec.setName("example.com");
|
||||
assertEquals("example", rec.getSld());
|
||||
|
||||
rec.setName("host");
|
||||
assertEquals("host", rec.getSld());
|
||||
|
||||
rec.setName(".dotstart");
|
||||
assertEquals(".dotstart", rec.getSld());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetSldWithZoneName() {
|
||||
RecordEntity rec = new RecordEntity();
|
||||
rec.setName("sub.example.com");
|
||||
rec.setZoneName("example.com");
|
||||
assertEquals("sub", rec.getSld());
|
||||
|
||||
rec.setName("my.sub.example.com");
|
||||
rec.setZoneName("example.com");
|
||||
assertEquals("my.sub", rec.getSld());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package codes.thischwa.cf.model;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class RecordTypeTest {
|
||||
|
||||
@Test
|
||||
void testGetType() {
|
||||
assertEquals("A", RecordType.A.getType());
|
||||
assertEquals("AAAA", RecordType.AAAA.getType());
|
||||
assertEquals("CNAME", RecordType.CNAME.getType());
|
||||
assertEquals("TXT", RecordType.TXT.getType());
|
||||
assertEquals("SRV", RecordType.SRV.getType());
|
||||
assertEquals("LOC", RecordType.LOC.getType());
|
||||
assertEquals("MX", RecordType.MX.getType());
|
||||
assertEquals("NS", RecordType.NS.getType());
|
||||
assertEquals("CAA", RecordType.CAA.getType());
|
||||
assertEquals("CERT", RecordType.CERT.getType());
|
||||
assertEquals("DNSKEY", RecordType.DNSKEY.getType());
|
||||
assertEquals("DS", RecordType.DS.getType());
|
||||
assertEquals("NAPTR", RecordType.NAPTR.getType());
|
||||
assertEquals("SMIMEA", RecordType.SMIMEA.getType());
|
||||
assertEquals("SSHFP", RecordType.SSHFP.getType());
|
||||
assertEquals("TLSA", RecordType.TLSA.getType());
|
||||
assertEquals("URI", RecordType.URI.getType());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testToString() {
|
||||
assertEquals("A", RecordType.A.toString());
|
||||
assertEquals("CNAME", RecordType.CNAME.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValueOf() {
|
||||
assertEquals(RecordType.A, RecordType.valueOf("A"));
|
||||
assertEquals(RecordType.CNAME, RecordType.valueOf("CNAME"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package codes.thischwa.cf.model;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Set;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class ZoneEntityTest {
|
||||
|
||||
@Test
|
||||
void testZoneEntity() {
|
||||
ZoneEntity zone = new ZoneEntity();
|
||||
zone.setId("zone-id");
|
||||
zone.setName("example.com");
|
||||
zone.setDevelopmentMode(7200);
|
||||
Set<String> ns = Set.of("ns1.cloudflare.com", "ns2.cloudflare.com");
|
||||
zone.setNameServers(ns);
|
||||
zone.setOriginalNameServers(ns);
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
zone.setCreatedOn(now);
|
||||
zone.setModifiedOn(now);
|
||||
zone.setActivatedOn(now);
|
||||
zone.setStatus("active");
|
||||
zone.setPaused(false);
|
||||
zone.setType("full");
|
||||
|
||||
assertEquals("zone-id", zone.getId());
|
||||
assertEquals("example.com", zone.getName());
|
||||
assertEquals(7200, zone.getDevelopmentMode());
|
||||
assertEquals(ns, zone.getNameServers());
|
||||
assertEquals(ns, zone.getOriginalNameServers());
|
||||
assertEquals(now, zone.getCreatedOn());
|
||||
assertEquals(now, zone.getModifiedOn());
|
||||
assertEquals(now, zone.getActivatedOn());
|
||||
assertEquals("active", zone.getStatus());
|
||||
assertFalse(zone.getPaused());
|
||||
assertEquals("full", zone.getType());
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<configuration debug="true">
|
||||
|
||||
<appender name="current"
|
||||
class="ch.qos.logback.core.ConsoleAppender">
|
||||
|
||||
Reference in New Issue
Block a user