add unit tests

This commit is contained in:
Manoj Kumar 2026-04-01 09:44:36 +05:30
parent c6abed1702
commit f1dcd00a9d
No known key found for this signature in database
GPG Key ID: E952B7234D2C6F88
8 changed files with 1878 additions and 203 deletions

View File

@ -18,13 +18,65 @@
package org.apache.cloudstack.dns.powerdns;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import org.apache.cloudstack.dns.exception.DnsOperationException;
import org.apache.cloudstack.dns.exception.DnsAuthenticationException;
import org.apache.cloudstack.dns.exception.DnsConflictException;
import org.apache.cloudstack.dns.exception.DnsNotFoundException;
import org.apache.http.StatusLine;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.junit.runner.RunWith;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
import org.springframework.test.util.ReflectionTestUtils;
import com.fasterxml.jackson.databind.JsonNode;
@RunWith(MockitoJUnitRunner.class)
public class PowerDnsClientTest {
@InjectMocks
PowerDnsClient client = new PowerDnsClient();
PowerDnsClient client;
CloseableHttpClient httpClientMock;
@Before
public void setUp() {
client = new PowerDnsClient();
httpClientMock = mock(CloseableHttpClient.class);
ReflectionTestUtils.setField(client, "httpClient", httpClientMock);
}
private CloseableHttpResponse createResponse(int statusCode, String jsonBody) {
CloseableHttpResponse responseMock = mock(CloseableHttpResponse.class);
StatusLine statusLineMock = mock(StatusLine.class);
when(responseMock.getStatusLine()).thenReturn(statusLineMock);
when(statusLineMock.getStatusCode()).thenReturn(statusCode);
if (jsonBody != null) {
when(responseMock.getEntity()).thenReturn(new StringEntity(jsonBody, StandardCharsets.UTF_8));
}
return responseMock;
}
private void mockHttpResponse(int statusCode, String jsonBody) throws IOException {
CloseableHttpResponse response = createResponse(statusCode, jsonBody);
when(httpClientMock.execute(any(HttpUriRequest.class))).thenReturn(response);
}
@Test
public void testNormalizeApexRecord() {
@ -80,4 +132,225 @@ public class PowerDnsClientTest {
result = client.normalizeRecordName("www", "example.com.");
assertEquals("www.example.com.", result);
}
@Test
public void testDiscoverAuthoritativeServerIdSuccess() throws Exception {
mockHttpResponse(200, "[{\"id\":\"localhost\", \"daemon_type\":\"authoritative\"}]");
String result = client.discoverAuthoritativeServerId("http://pdns:8081", null, "apikey");
assertEquals("localhost", result);
}
@Test
public void testDiscoverAuthoritativeServerIdFallback() throws Exception {
mockHttpResponse(200, "[{\"id\":\"server1\", \"daemon_type\":\"recursor\"}, {\"id\":\"server2\", \"daemon_type\":\"authoritative\"}]");
String result = client.discoverAuthoritativeServerId("http://pdns", 8081, "apikey");
assertEquals("server2", result);
}
@Test(expected = DnsOperationException.class)
public void testDiscoverAuthoritativeServerIdEmpty() throws Exception {
mockHttpResponse(200, "[]");
client.discoverAuthoritativeServerId("http://pdns", 8081, "apikey");
}
@Test(expected = DnsOperationException.class)
public void testDiscoverAuthoritativeServerIdNoAuthoritative() throws Exception {
mockHttpResponse(200, "[{\"id\":\"server1\", \"daemon_type\":\"recursor\"}]");
client.discoverAuthoritativeServerId("http://pdns", 8081, "apikey");
}
@Test
public void testValidateServerIdSuccess() throws Exception {
mockHttpResponse(200, "{\"id\":\"abc\", \"daemon_type\":\"authoritative\"}");
String result = client.validateServerId("http://pdns", 8081, "apikey", "abc");
assertEquals("abc", result);
}
@Test(expected = DnsOperationException.class)
public void testValidateServerIdNotAuthoritative() throws Exception {
mockHttpResponse(200, "{\"id\":\"abc\", \"daemon_type\":\"recursor\"}");
client.validateServerId("http://pdns", 8081, "apikey", "abc");
}
@Test
public void testResolveServerIdWithExternalId() throws Exception {
mockHttpResponse(200, "{\"id\":\"abc\", \"daemon_type\":\"authoritative\"}");
String result = client.resolveServerId("http://pdns", 8081, "apikey", "abc");
assertEquals("abc", result);
}
@Test
public void testResolveServerIdWithoutExternalId() throws Exception {
mockHttpResponse(200, "[{\"id\":\"localhost\", \"daemon_type\":\"authoritative\"}]");
String result = client.resolveServerId("http://pdns", 8081, "apikey", null);
assertEquals("localhost", result);
}
@Test
public void testCreateZone() throws Exception {
when(httpClientMock.execute(any(HttpUriRequest.class))).thenAnswer(new Answer<CloseableHttpResponse>() {
@Override
public CloseableHttpResponse answer(InvocationOnMock invocation) {
HttpUriRequest request = invocation.getArgument(0);
if (request.getMethod().equals("GET")) {
return createResponse(200, "{\"id\":\"abc\", \"daemon_type\":\"authoritative\"}");
}
if (request.getMethod().equals("POST")) {
return createResponse(201, "{\"id\":\"example.com.\"}");
}
return createResponse(500, null);
}
});
String result = client.createZone("http://pdns", 8081, "apikey", "abc", "example.com", "Native", false, Arrays.asList("ns1.com"));
assertEquals("example.com.", result);
}
@Test
public void testUpdateZone() throws Exception {
when(httpClientMock.execute(any(HttpUriRequest.class))).thenAnswer(new Answer<CloseableHttpResponse>() {
@Override
public CloseableHttpResponse answer(InvocationOnMock invocation) {
HttpUriRequest request = invocation.getArgument(0);
if (request.getMethod().equals("GET")) {
return createResponse(200, "{\"id\":\"abc\", \"daemon_type\":\"authoritative\"}");
}
if (request.getMethod().equals("PUT")) {
return createResponse(204, null);
}
return createResponse(500, null);
}
});
client.updateZone("http://pdns", 8081, "apikey", "abc", "example.com", "Native", true, Arrays.asList("ns1.com"));
// No exception means success
}
@Test
public void testDeleteZone() throws Exception {
when(httpClientMock.execute(any(HttpUriRequest.class))).thenAnswer(new Answer<CloseableHttpResponse>() {
@Override
public CloseableHttpResponse answer(InvocationOnMock invocation) {
HttpUriRequest request = invocation.getArgument(0);
if (request.getMethod().equals("GET")) {
return createResponse(200, "{\"id\":\"abc\", \"daemon_type\":\"authoritative\"}");
}
if (request.getMethod().equals("DELETE")) {
return createResponse(204, null);
}
return createResponse(500, null);
}
});
client.deleteZone("http://pdns", 8081, "apikey", "abc", "example.com");
}
@Test
public void testModifyRecord() throws Exception {
when(httpClientMock.execute(any(HttpUriRequest.class))).thenAnswer(new Answer<CloseableHttpResponse>() {
@Override
public CloseableHttpResponse answer(InvocationOnMock invocation) {
HttpUriRequest request = invocation.getArgument(0);
if (request.getMethod().equals("GET")) {
return createResponse(200, "{\"id\":\"abc\", \"daemon_type\":\"authoritative\"}");
}
if (request.getMethod().equals("PATCH")) {
return createResponse(204, null);
}
return createResponse(500, null);
}
});
String result = client.modifyRecord("http://pdns", 8081, "apikey", "abc", "example.com", "www", "A", 300, Arrays.asList("1.2.3.4"), "REPLACE");
assertEquals("www.example.com", result);
}
@Test
public void testModifyRecordApex() throws Exception {
when(httpClientMock.execute(any(HttpUriRequest.class))).thenAnswer(new Answer<CloseableHttpResponse>() {
@Override
public CloseableHttpResponse answer(InvocationOnMock invocation) {
HttpUriRequest request = invocation.getArgument(0);
if (request.getMethod().equals("GET")) {
return createResponse(200, "{\"id\":\"abc\", \"daemon_type\":\"authoritative\"}");
}
if (request.getMethod().equals("PATCH")) {
return createResponse(204, null);
}
return createResponse(500, null);
}
});
String result = client.modifyRecord("http://pdns", 8081, "apikey", "abc", "example.com", "@", "A", 300, Arrays.asList("1.2.3.4"), "REPLACE");
assertEquals("example.com", result);
}
@Test
public void testListRecords() throws Exception {
when(httpClientMock.execute(any(HttpUriRequest.class))).thenAnswer(new Answer<CloseableHttpResponse>() {
@Override
public CloseableHttpResponse answer(InvocationOnMock invocation) {
HttpUriRequest request = invocation.getArgument(0);
// validateServerId uses /servers/abc
// listRecords uses /servers/abc/zones/example.com.
if (request.getURI().getPath().endsWith("abc")) {
return createResponse(200, "{\"id\":\"abc\", \"daemon_type\":\"authoritative\"}");
}
if (request.getURI().getPath().endsWith("example.com.")) {
return createResponse(200, "{\"rrsets\":[{\"name\":\"www.example.com.\",\"type\":\"A\"}]}");
}
return createResponse(500, null);
}
});
Iterable<JsonNode> records = client.listRecords("http://pdns", 8081, "apikey", "abc", "example.com");
assertNotNull(records);
assertTrue(records.iterator().hasNext());
assertEquals("www.example.com.", records.iterator().next().path("name").asText());
}
@Test
public void testListRecordsEmpty() throws Exception {
when(httpClientMock.execute(any(HttpUriRequest.class))).thenAnswer(new Answer<CloseableHttpResponse>() {
@Override
public CloseableHttpResponse answer(InvocationOnMock invocation) {
HttpUriRequest request = invocation.getArgument(0);
if (request.getURI().getPath().endsWith("abc")) {
return createResponse(200, "{\"id\":\"abc\", \"daemon_type\":\"authoritative\"}");
}
if (request.getURI().getPath().endsWith("example.com.")) {
return createResponse(200, "{}");
}
return createResponse(500, null);
}
});
Iterable<JsonNode> records = client.listRecords("http://pdns", 8081, "apikey", "abc", "example.com");
assertNotNull(records);
assertTrue(!records.iterator().hasNext());
}
@Test(expected = DnsNotFoundException.class)
public void testExecuteThrowsNotFound() throws Exception {
mockHttpResponse(404, "Not Found");
client.validateServerId("http://pdns", 8081, "apikey", "abc");
}
@Test(expected = DnsAuthenticationException.class)
public void testExecuteThrowsAuthError() throws Exception {
mockHttpResponse(401, "Unauthorized");
client.validateServerId("http://pdns", 8081, "apikey", "abc");
}
@Test(expected = DnsConflictException.class)
public void testExecuteThrowsConflictError() throws Exception {
mockHttpResponse(409, "Conflict");
client.validateServerId("http://pdns", 8081, "apikey", "abc");
}
@Test(expected = DnsOperationException.class)
public void testExecuteThrowsUnexpectedStatus() throws Exception {
mockHttpResponse(500, "Server Error");
client.validateServerId("http://pdns", 8081, "apikey", "abc");
}
}

View File

@ -0,0 +1,391 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.dns.powerdns;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import org.apache.cloudstack.dns.DnsRecord;
import org.apache.cloudstack.dns.DnsRecord.RecordType;
import org.apache.cloudstack.dns.DnsServer;
import org.apache.cloudstack.dns.DnsZone;
import org.apache.cloudstack.dns.DnsProviderType;
import org.apache.cloudstack.dns.exception.DnsProviderException;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.test.util.ReflectionTestUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
@RunWith(MockitoJUnitRunner.class)
public class PowerDnsProviderTest {
private static final ObjectMapper MAPPER = new ObjectMapper();
private PowerDnsProvider provider;
private PowerDnsClient clientMock;
private DnsServer serverMock;
private DnsZone zoneMock;
@Before
public void setUp() {
provider = new PowerDnsProvider();
clientMock = mock(PowerDnsClient.class);
serverMock = mock(DnsServer.class);
zoneMock = mock(DnsZone.class);
ReflectionTestUtils.setField(provider, "client", clientMock);
when(serverMock.getUrl()).thenReturn("http://pdns:8081");
when(serverMock.getApiKey()).thenReturn("secret");
when(serverMock.getPort()).thenReturn(8081);
when(serverMock.getExternalServerId()).thenReturn("localhost");
when(serverMock.getNameServers()).thenReturn(Arrays.asList("ns1.example.com"));
when(zoneMock.getName()).thenReturn("example.com");
}
@Test
public void testGetProviderType() {
assertEquals(DnsProviderType.PowerDNS, provider.getProviderType());
}
@Test
public void testConfigureCreatesClientWhenNull() {
PowerDnsProvider freshProvider = new PowerDnsProvider();
boolean result = freshProvider.configure("test", new HashMap<>());
assertTrue(result);
assertNotNull(ReflectionTestUtils.getField(freshProvider, "client"));
}
@Test
public void testConfigureDoesNotReplaceExistingClient() {
PowerDnsClient existingClient = mock(PowerDnsClient.class);
ReflectionTestUtils.setField(provider, "client", existingClient);
boolean result = provider.configure("test", new HashMap<>());
assertTrue(result);
assertEquals(existingClient, ReflectionTestUtils.getField(provider, "client"));
}
@Test
public void testStopClosesClient() {
boolean result = provider.stop();
assertTrue(result);
verify(clientMock, times(1)).close();
}
@Test
public void testStopWithNullClientSucceeds() {
ReflectionTestUtils.setField(provider, "client", null);
boolean result = provider.stop();
assertTrue(result);
}
@Test(expected = IllegalArgumentException.class)
public void testValidateServerFieldsNullUrl() {
when(serverMock.getUrl()).thenReturn(null);
provider.validateRequiredServerFields(serverMock);
}
@Test(expected = IllegalArgumentException.class)
public void testValidateServerFieldsBlankUrl() {
when(serverMock.getUrl()).thenReturn(" ");
provider.validateRequiredServerFields(serverMock);
}
@Test(expected = IllegalArgumentException.class)
public void testValidateServerFieldsNullApiKey() {
when(serverMock.getApiKey()).thenReturn(null);
provider.validateRequiredServerFields(serverMock);
}
@Test(expected = IllegalArgumentException.class)
public void testValidateServerFieldsBlankApiKey() {
when(serverMock.getApiKey()).thenReturn("");
provider.validateRequiredServerFields(serverMock);
}
@Test(expected = IllegalArgumentException.class)
public void testValidateServerAndZoneFieldsBlankZoneName() {
when(zoneMock.getName()).thenReturn(" ");
provider.validateRequiredServerAndZoneFields(serverMock, zoneMock);
}
@Test(expected = IllegalArgumentException.class)
public void testValidateServerAndZoneFieldsNullZoneName() {
when(zoneMock.getName()).thenReturn(null);
provider.validateRequiredServerAndZoneFields(serverMock, zoneMock);
}
@Test
public void testValidateDelegatesToClient() throws DnsProviderException {
when(clientMock.validateServerId(anyString(), anyInt(), anyString(), anyString())).thenReturn("localhost");
provider.validate(serverMock);
verify(clientMock).validateServerId("http://pdns:8081", 8081, "secret", "localhost");
}
@Test(expected = IllegalArgumentException.class)
public void testValidateThrowsWhenServerUrlBlank() throws DnsProviderException {
when(serverMock.getUrl()).thenReturn("");
provider.validate(serverMock);
}
@Test
public void testValidateAndResolveServer() throws Exception {
when(clientMock.resolveServerId(anyString(), anyInt(), anyString(), anyString())).thenReturn("localhost");
String result = provider.validateAndResolveServer(serverMock);
assertEquals("localhost", result);
verify(clientMock).resolveServerId("http://pdns:8081", 8081, "secret", "localhost");
}
@Test(expected = IllegalArgumentException.class)
public void testValidateAndResolveServerThrowsWhenUrlBlank() throws Exception {
when(serverMock.getUrl()).thenReturn(null);
provider.validateAndResolveServer(serverMock);
}
@Test
public void testProvisionZoneDelegatesToClient() throws DnsProviderException {
when(clientMock.createZone(anyString(), anyInt(), anyString(), anyString(), anyString(), anyString(), eq(false), anyList())).thenReturn("example.com.");
String zoneId = provider.provisionZone(serverMock, zoneMock);
assertEquals("example.com.", zoneId);
verify(clientMock).createZone("http://pdns:8081", 8081, "secret", "localhost", "example.com",
"Native", false, Arrays.asList("ns1.example.com"));
}
@Test(expected = IllegalArgumentException.class)
public void testProvisionZoneThrowsWhenZoneNameBlank() throws DnsProviderException {
when(zoneMock.getName()).thenReturn(null);
provider.provisionZone(serverMock, zoneMock);
}
@Test
public void testDeleteZoneDelegatesToClient() throws DnsProviderException {
provider.deleteZone(serverMock, zoneMock);
verify(clientMock).deleteZone("http://pdns:8081", 8081, "secret", "localhost", "example.com");
}
@Test(expected = IllegalArgumentException.class)
public void testDeleteZoneThrowsWhenZoneNameBlank() throws DnsProviderException {
when(zoneMock.getName()).thenReturn("");
provider.deleteZone(serverMock, zoneMock);
}
@Test
public void testUpdateZoneDelegatesToClient() throws DnsProviderException {
provider.updateZone(serverMock, zoneMock);
verify(clientMock).updateZone("http://pdns:8081", 8081, "secret", "localhost", "example.com",
"Native", false, Arrays.asList("ns1.example.com"));
}
@Test
public void testAddRecordDelegatesToClient() throws DnsProviderException {
DnsRecord record = new DnsRecord("www", RecordType.A, Arrays.asList("1.2.3.4"), 300);
when(clientMock.modifyRecord(anyString(), anyInt(), anyString(), anyString(), anyString(),
anyString(), anyString(), anyLong(), anyList(), anyString())).thenReturn("www.example.com");
String result = provider.addRecord(serverMock, zoneMock, record);
assertEquals("www.example.com", result);
verify(clientMock).modifyRecord("http://pdns:8081", 8081, "secret", "localhost", "example.com",
"www", "A", 300L, Arrays.asList("1.2.3.4"), "REPLACE");
}
@Test(expected = IllegalArgumentException.class)
public void testAddRecordThrowsWhenServerUrlBlank() throws DnsProviderException {
when(serverMock.getUrl()).thenReturn("");
DnsRecord record = new DnsRecord("www", RecordType.A, Arrays.asList("1.2.3.4"), 300);
provider.addRecord(serverMock, zoneMock, record);
}
@Test
public void testUpdateRecordDelegatesToAddRecord() throws DnsProviderException {
DnsRecord record = new DnsRecord("mail", RecordType.MX, Arrays.asList("10 mail.example.com"), 300);
when(clientMock.modifyRecord(anyString(), anyInt(), anyString(), anyString(), anyString(),
anyString(), anyString(), anyLong(), anyList(), anyString())).thenReturn("mail.example.com");
String result = provider.updateRecord(serverMock, zoneMock, record);
assertEquals("mail.example.com", result);
verify(clientMock).modifyRecord(anyString(), anyInt(), anyString(), anyString(), anyString(),
eq("mail"), eq("MX"), eq(300L), eq(Arrays.asList("10 mail.example.com")), eq("REPLACE"));
}
@Test
public void testDeleteRecordDelegatesToClientWithDeleteChangeType() throws DnsProviderException {
DnsRecord record = new DnsRecord("old", RecordType.CNAME, Arrays.asList("target.com"), 600);
when(clientMock.modifyRecord(anyString(), anyInt(), anyString(), anyString(), anyString(),
anyString(), anyString(), anyLong(), anyList(), anyString())).thenReturn("old.example.com");
String result = provider.deleteRecord(serverMock, zoneMock, record);
assertEquals("old.example.com", result);
verify(clientMock).modifyRecord(anyString(), anyInt(), anyString(), anyString(), anyString(),
eq("old"), eq("CNAME"), eq(600L), eq(Arrays.asList("target.com")), eq("DELETE"));
}
@Test
public void testApplyRecordPassesChangeTypeToClient() throws DnsProviderException {
DnsRecord record = new DnsRecord("txt", RecordType.TXT, Arrays.asList("v=spf1 include:example.com ~all"), 3600);
when(clientMock.modifyRecord(anyString(), anyInt(), anyString(), anyString(), anyString(),
anyString(), anyString(), anyLong(), anyList(), anyString())).thenReturn("txt.example.com");
provider.applyRecord("http://pdns:8081", 8081, "secret", "localhost", "example.com",
record, PowerDnsProvider.ChangeType.REPLACE);
verify(clientMock).modifyRecord("http://pdns:8081", 8081, "secret", "localhost", "example.com",
"txt", "TXT", 3600L, Arrays.asList("v=spf1 include:example.com ~all"), "REPLACE");
}
@Test
public void testListRecordsParsesRrsets() throws DnsProviderException {
ObjectNode aRecord = MAPPER.createObjectNode();
aRecord.put("name", "www.example.com.");
aRecord.put("type", "A");
aRecord.put("ttl", 300);
ArrayNode records = aRecord.putArray("records");
records.addObject().put("content", "1.2.3.4");
ObjectNode mxRecord = MAPPER.createObjectNode();
mxRecord.put("name", "example.com.");
mxRecord.put("type", "MX");
mxRecord.put("ttl", 600);
ArrayNode mxRecords = mxRecord.putArray("records");
mxRecords.addObject().put("content", "10 mail.example.com");
when(clientMock.listRecords(anyString(), anyInt(), anyString(), anyString(), anyString()))
.thenReturn(Arrays.asList(aRecord, mxRecord));
List<DnsRecord> result = provider.listRecords(serverMock, zoneMock);
assertEquals(2, result.size());
DnsRecord first = result.get(0);
assertEquals("www.example.com.", first.getName());
assertEquals(RecordType.A, first.getType());
assertEquals(300, first.getTtl());
assertEquals(Arrays.asList("1.2.3.4"), first.getContents());
DnsRecord second = result.get(1);
assertEquals("example.com.", second.getName());
assertEquals(RecordType.MX, second.getType());
assertEquals(600, second.getTtl());
assertEquals(Arrays.asList("10 mail.example.com"), second.getContents());
}
@Test
public void testListRecordsSkipsSoaRecords() throws DnsProviderException {
ObjectNode soaRecord = MAPPER.createObjectNode();
soaRecord.put("name", "example.com.");
soaRecord.put("type", "SOA");
soaRecord.put("ttl", 3600);
soaRecord.putArray("records").addObject().put("content", "ns1.example.com. admin.example.com. ...");
when(clientMock.listRecords(anyString(), anyInt(), anyString(), anyString(), anyString()))
.thenReturn(Collections.singletonList(soaRecord));
List<DnsRecord> result = provider.listRecords(serverMock, zoneMock);
assertTrue(result.isEmpty());
}
@Test
public void testListRecordsSkipsUnknownRecordTypes() throws DnsProviderException {
ObjectNode unknownRecord = MAPPER.createObjectNode();
unknownRecord.put("name", "test.example.com.");
unknownRecord.put("type", "UNKNOWNTYPE");
unknownRecord.put("ttl", 300);
unknownRecord.putArray("records").addObject().put("content", "some-data");
when(clientMock.listRecords(anyString(), anyInt(), anyString(), anyString(), anyString()))
.thenReturn(Collections.singletonList(unknownRecord));
List<DnsRecord> result = provider.listRecords(serverMock, zoneMock);
assertTrue(result.isEmpty());
}
@Test
public void testListRecordsIgnoresEmptyContentEntries() throws DnsProviderException {
ObjectNode aRecord = MAPPER.createObjectNode();
aRecord.put("name", "host.example.com.");
aRecord.put("type", "A");
aRecord.put("ttl", 300);
ArrayNode records = aRecord.putArray("records");
records.addObject().put("content", "");
records.addObject().put("content", "5.6.7.8");
when(clientMock.listRecords(anyString(), anyInt(), anyString(), anyString(), anyString()))
.thenReturn(Collections.singletonList(aRecord));
List<DnsRecord> result = provider.listRecords(serverMock, zoneMock);
assertEquals(1, result.size());
assertEquals(Collections.singletonList("5.6.7.8"), result.get(0).getContents());
}
@Test
public void testListRecordsReturnsEmptyListWhenClientReturnsEmpty() throws DnsProviderException {
when(clientMock.listRecords(anyString(), anyInt(), anyString(), anyString(), anyString()))
.thenReturn(Collections.emptyList());
List<DnsRecord> result = provider.listRecords(serverMock, zoneMock);
assertNotNull(result);
assertTrue(result.isEmpty());
}
@Test(expected = DnsProviderException.class)
public void testListRecordsPropagatesClientException() throws DnsProviderException {
when(clientMock.listRecords(anyString(), anyInt(), anyString(), anyString(), anyString()))
.thenThrow(mock(DnsProviderException.class));
provider.listRecords(serverMock, zoneMock);
}
@Test(expected = IllegalArgumentException.class)
public void testListRecordsThrowsWhenZoneNameBlank() throws DnsProviderException {
when(zoneMock.getName()).thenReturn("");
provider.listRecords(serverMock, zoneMock);
}
@Test
public void testChangeTypeValues() {
assertEquals("REPLACE", PowerDnsProvider.ChangeType.REPLACE.name());
assertEquals("DELETE", PowerDnsProvider.ChangeType.DELETE.name());
}
}

View File

@ -34,7 +34,6 @@ import org.apache.cloudstack.api.InternalIdentity;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.framework.events.EventDistributor;
import org.apache.cloudstack.framework.messagebus.MessageBus;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
@ -86,8 +85,6 @@ public class ActionEventUtils {
EntityManager entityMgr;
@Inject
ConfigurationDao configDao;
@Inject
MessageBus messageBus;
public ActionEventUtils() {
}
@ -100,7 +97,6 @@ public class ActionEventUtils {
s_projectDao = projectDao;
s_entityMgr = entityMgr;
s_configDao = configDao;
messageBus = messageBus;
}
public static Long onActionEvent(Long userId, Long accountId, Long domainId, String type, String description, Long resourceId, String resourceType) {

View File

@ -1,196 +0,0 @@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
package org.apache.cloudstack.dns;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.framework.events.Event;
import org.apache.cloudstack.framework.events.EventBus;
import org.apache.cloudstack.framework.events.EventBusException;
import org.apache.cloudstack.framework.events.EventSubscriber;
import org.apache.cloudstack.framework.events.EventTopic;
import org.springframework.stereotype.Component;
import com.cloud.event.EventTypes;
import com.cloud.network.Network;
import com.cloud.network.dao.NetworkDao;
import com.cloud.utils.StringUtils;
import com.cloud.utils.component.ManagerBase;
import com.cloud.vm.Nic;
import com.cloud.vm.NicVO;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.dao.NicDao;
import com.cloud.vm.dao.NicDetailsDao;
import com.cloud.vm.dao.VMInstanceDao;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
@Component
public class DnsVmLifecycleListener extends ManagerBase implements EventSubscriber {
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
@Inject
private EventBus eventBus = null;
@Inject
VMInstanceDao vmInstanceDao;
@Inject
NetworkDao networkDao;
@Inject
NicDao nicDao;
@Inject
DnsProviderManager providerManager;
@Inject
NicDetailsDao nicDetailsDao;
@Override
public boolean configure(final String name, final Map<String, Object> params) {
if (eventBus == null) {
logger.info("EventBus is not available; DNS Instance lifecycle listener will not subscribe to events");
return true;
}
try {
eventBus.subscribe(new EventTopic(null, EventTypes.EVENT_VM_CREATE, null, null, null), this);
eventBus.subscribe(new EventTopic(null, EventTypes.EVENT_VM_START, null, null, null), this);
eventBus.subscribe(new EventTopic(null, EventTypes.EVENT_VM_STOP, null, null, null), this);
eventBus.subscribe(new EventTopic(null, EventTypes.EVENT_VM_DESTROY, null, null, null), this);
eventBus.subscribe(new EventTopic(null, EventTypes.EVENT_NIC_CREATE, null, null, null), this);
eventBus.subscribe(new EventTopic(null, EventTypes.EVENT_NIC_DELETE, null, null, null), this);
eventBus.subscribe(new EventTopic(null, EventTypes.EVENT_DNS_RECORD_DELETE, null, null, null), this);
} catch (EventBusException ex) {
logger.error("Failed to subscribe DnsVmLifecycleListener to EventBus", ex);
}
return true;
}
@Override
public void onEvent(Event event) {
JsonNode descJson = parseEventDescription(event);
if (!isEventCompleted(descJson)) {
return;
}
String eventType = event.getEventType();
String resourceUuid = event.getResourceUUID();
try {
switch (eventType) {
case EventTypes.EVENT_VM_CREATE:
case EventTypes.EVENT_VM_START:
handleVmEvent(resourceUuid, true);
break;
case EventTypes.EVENT_VM_STOP:
case EventTypes.EVENT_VM_DESTROY:
handleVmEvent(resourceUuid, false);
break;
case EventTypes.EVENT_NIC_CREATE:
handleNicEvent(descJson, true);
break;
case EventTypes.EVENT_NIC_DELETE:
handleNicEvent(descJson, false);
break;
default:
break;
}
} catch (Exception ex) {
logger.error("Failed to process DNS lifecycle event: type={}, resourceUuid={}",
eventType, event.getResourceUUID(), ex);
}
}
private void handleNicEvent(JsonNode eventDesc, boolean isAddDnsRecord) {
JsonNode nicUuid = eventDesc.get("Nic");
JsonNode vmUuid = eventDesc.get("VirtualMachine");
if (nicUuid == null || nicUuid.isNull() || vmUuid == null || vmUuid.isNull()) {
logger.warn("Event has missing data to work on: {}", eventDesc);
return;
}
VMInstanceVO vmInstanceVO = vmInstanceDao.findByUuid(vmUuid.asText());
if (vmInstanceVO == null) {
logger.error("Unable to find Instance with ID: {}", vmUuid);
return;
}
Nic nic = nicDao.findByUuidIncludingRemoved(nicUuid.asText());
if (nic == null) {
logger.error("NIC is not found for the ID: {}", nicUuid);
return;
}
Network network = networkDao.findById(nic.getNetworkId());
if (network == null || !Network.GuestType.Shared.equals(network.getGuestType())) {
logger.warn("Network is not eligible for DNS record registration");
return;
}
processEventForDnsRecord(vmInstanceVO, network, nic, isAddDnsRecord);
}
private void handleVmEvent(String vmUuid, boolean isAddDnsRecord) {
VMInstanceVO vmInstanceVO = vmInstanceDao.findByUuidIncludingRemoved(vmUuid);
if (vmInstanceVO == null) {
logger.error("Unable to find Instance with ID: {}", vmUuid);
return;
}
List<NicVO> vmNics = nicDao.listByVmIdIncludingRemoved(vmInstanceVO.getId());
for (NicVO nic : vmNics) {
Network network = networkDao.findById(nic.getNetworkId());
if (network == null || !Network.GuestType.Shared.equals(network.getGuestType())) {
continue;
}
processEventForDnsRecord(vmInstanceVO, network, nic, isAddDnsRecord);
}
}
void processEventForDnsRecord(VMInstanceVO vmInstanceVO, Network network, Nic nic, boolean isAddDnsRecord) {
if (isAddDnsRecord) {
providerManager.addDnsRecordForVM(vmInstanceVO, network, nic);
} else {
providerManager.deleteDnsRecordForVM(vmInstanceVO, network, nic);
}
}
private JsonNode parseEventDescription(Event event) {
String rawDescription = event.getDescription();
if (StringUtils.isBlank(rawDescription)) {
return null;
}
try {
return OBJECT_MAPPER.readTree(rawDescription);
} catch (Exception ex) {
logger.warn("parseEventDescription: failed to parse description for event [{}]: {}",
event.getEventType(), ex.getMessage());
return null;
}
}
private boolean isEventCompleted(JsonNode descJson) {
if (descJson == null) {
return false;
}
JsonNode statusNode = descJson.get(ApiConstants.STATUS);
if (statusNode == null || statusNode.isNull()) {
return false;
}
logger.debug("Processing Event: {}", descJson);
return ApiConstants.COMPLETED.equalsIgnoreCase(statusNode.asText());
}
}

View File

@ -0,0 +1,892 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.dns;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.apache.cloudstack.api.command.user.dns.CreateDnsZoneCmd;
import org.apache.cloudstack.api.command.user.dns.DeleteDnsServerCmd;
import org.apache.cloudstack.api.command.user.dns.DisassociateDnsZoneFromNetworkCmd;
import org.apache.cloudstack.api.command.user.dns.ListDnsRecordsCmd;
import org.apache.cloudstack.api.command.user.dns.UpdateDnsZoneCmd;
import org.apache.cloudstack.api.response.DnsRecordResponse;
import org.apache.cloudstack.api.response.DnsServerResponse;
import org.apache.cloudstack.api.response.DnsZoneNetworkMapResponse;
import org.apache.cloudstack.api.response.DnsZoneResponse;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.dns.dao.DnsServerDao;
import org.apache.cloudstack.dns.dao.DnsServerJoinDao;
import org.apache.cloudstack.dns.dao.DnsZoneDao;
import org.apache.cloudstack.dns.dao.DnsZoneJoinDao;
import org.apache.cloudstack.dns.dao.DnsZoneNetworkMapDao;
import org.apache.cloudstack.dns.exception.DnsConflictException;
import org.apache.cloudstack.dns.exception.DnsNotFoundException;
import org.apache.cloudstack.dns.exception.DnsProviderException;
import org.apache.cloudstack.dns.exception.DnsTransportException;
import org.apache.cloudstack.dns.vo.DnsServerJoinVO;
import org.apache.cloudstack.dns.vo.DnsServerVO;
import org.apache.cloudstack.dns.vo.DnsZoneJoinVO;
import org.apache.cloudstack.dns.vo.DnsZoneNetworkMapVO;
import org.apache.cloudstack.dns.vo.DnsZoneVO;
import org.apache.cloudstack.framework.messagebus.MessageBus;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.test.util.ReflectionTestUtils;
import com.cloud.domain.dao.DomainDao;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.network.Network;
import com.cloud.network.dao.NetworkDao;
import com.cloud.network.dao.NetworkVO;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.user.AccountVO;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.db.TransactionCallback;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.vm.NicDetailVO;
import com.cloud.vm.NicVO;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.dao.NicDao;
import com.cloud.vm.dao.NicDetailsDao;
import com.cloud.vm.dao.VMInstanceDao;
@RunWith(MockitoJUnitRunner.class)
public class DnsProviderManagerImplTest {
private static final long ACCOUNT_ID = 1L;
private static final long DOMAIN_ID = 10L;
private static final long SERVER_ID = 100L;
private static final long ZONE_ID = 200L;
private static final long NETWORK_ID = 300L;
@InjectMocks
DnsProviderManagerImpl manager;
@Mock AccountManager accountMgr;
@Mock DnsServerDao dnsServerDao;
@Mock DnsZoneDao dnsZoneDao;
@Mock DnsZoneJoinDao dnsZoneJoinDao;
@Mock DnsServerJoinDao dnsServerJoinDao;
@Mock DnsZoneNetworkMapDao dnsZoneNetworkMapDao;
@Mock NetworkDao networkDao;
@Mock DomainDao domainDao;
@Mock NicDao nicDao;
@Mock NicDetailsDao nicDetailsDao;
@Mock MessageBus messageBus;
@Mock VMInstanceDao vmInstanceDao;
@Mock DnsProvider dnsProviderMock;
@Mock Account callerMock;
private MockedStatic<CallContext> callContextMocked;
private CallContext callContextMock;
// Support VOs
private DnsServerVO serverVO;
private DnsZoneVO zoneVO;
@Before
public void setUp() throws Exception {
callContextMocked = Mockito.mockStatic(CallContext.class);
callContextMock = mock(CallContext.class);
callContextMocked.when(CallContext::current).thenReturn(callContextMock);
when(callContextMock.getCallingAccount()).thenReturn(callerMock);
when(callerMock.getId()).thenReturn(ACCOUNT_ID);
when(callerMock.getDomainId()).thenReturn(DOMAIN_ID);
serverVO = Mockito.spy(new DnsServerVO("test-server", "http://pdns:8081", 8081, "localhost",
DnsProviderType.PowerDNS, null, "apikey", false, null,
Collections.singletonList("ns1.example.com"), ACCOUNT_ID, DOMAIN_ID));
Mockito.lenient().doReturn(SERVER_ID).when(serverVO).getId();
zoneVO = Mockito.spy(new DnsZoneVO("example.com", DnsZone.ZoneType.Public, SERVER_ID, ACCOUNT_ID, DOMAIN_ID, "Test zone"));
Mockito.lenient().doReturn(ZONE_ID).when(zoneVO).getId();
when(dnsProviderMock.getProviderType()).thenReturn(DnsProviderType.PowerDNS);
manager.setDnsProviders(Collections.singletonList(dnsProviderMock));
doNothing().when(accountMgr).checkAccess(any(Account.class), nullable(org.apache.cloudstack.acl.SecurityChecker.AccessType.class), eq(true), any());
}
@After
public void tearDown() {
callContextMocked.close();
}
@Test(expected = CloudRuntimeException.class)
public void testGetProviderByTypeNull() {
// Setting providers to empty to force lookup failure
manager.setDnsProviders(Collections.emptyList());
// Trigger via provisionDnsZone which calls getProviderByType
when(dnsZoneDao.findById(ZONE_ID)).thenReturn(zoneVO);
when(dnsServerDao.findById(SERVER_ID)).thenReturn(serverVO);
manager.provisionDnsZone(ZONE_ID);
}
@Test
public void testListProviderNamesReturnsList() {
List<String> names = manager.listProviderNames();
assertEquals(1, names.size());
assertEquals("PowerDNS", names.get(0));
}
@Test
public void testListProviderNamesWithNullProviders() {
manager.setDnsProviders(null);
List<String> names = manager.listProviderNames();
assertTrue(names.isEmpty());
}
@Test(expected = InvalidParameterValueException.class)
public void testAllocateDnsZoneBlankName() {
CreateDnsZoneCmd cmd = mock(CreateDnsZoneCmd.class);
when(cmd.getName()).thenReturn(" ");
manager.allocateDnsZone(cmd);
}
@Test(expected = InvalidParameterValueException.class)
public void testAllocateDnsZoneServerNotFound() {
CreateDnsZoneCmd cmd = mock(CreateDnsZoneCmd.class);
when(cmd.getName()).thenReturn("example.com");
when(cmd.getDnsServerId()).thenReturn(SERVER_ID);
when(dnsServerDao.findById(SERVER_ID)).thenReturn(null);
manager.allocateDnsZone(cmd);
}
@Test(expected = InvalidParameterValueException.class)
public void testAllocateDnsZoneAlreadyExists() {
CreateDnsZoneCmd cmd = mock(CreateDnsZoneCmd.class);
when(cmd.getName()).thenReturn("example.com");
when(cmd.getDnsServerId()).thenReturn(SERVER_ID);
when(cmd.getType()).thenReturn(DnsZone.ZoneType.Public);
when(dnsServerDao.findById(SERVER_ID)).thenReturn(serverVO);
Mockito.doReturn(SERVER_ID).when(serverVO).getId();
Mockito.doReturn(ACCOUNT_ID).when(serverVO).getAccountId();
when(dnsZoneDao.findByNameServerAndType(anyString(), anyLong(), any())).thenReturn(zoneVO);
manager.allocateDnsZone(cmd);
}
@Test
public void testAllocateDnsZoneOwnerSuccess() {
CreateDnsZoneCmd cmd = mock(CreateDnsZoneCmd.class);
when(cmd.getName()).thenReturn("example.com");
when(cmd.getDnsServerId()).thenReturn(SERVER_ID);
when(cmd.getType()).thenReturn(DnsZone.ZoneType.Public);
when(cmd.getDescription()).thenReturn("desc");
when(dnsServerDao.findById(SERVER_ID)).thenReturn(serverVO);
Mockito.doReturn(SERVER_ID).when(serverVO).getId();
Mockito.doReturn(ACCOUNT_ID).when(serverVO).getAccountId();
when(dnsZoneDao.findByNameServerAndType(anyString(), anyLong(), any())).thenReturn(null);
when(dnsZoneDao.persist(any(DnsZoneVO.class))).thenReturn(zoneVO);
DnsZone result = manager.allocateDnsZone(cmd);
assertNotNull(result);
}
@Test(expected = PermissionDeniedException.class)
public void testAllocateDnsZoneNonOwnerPrivateServer() {
CreateDnsZoneCmd cmd = mock(CreateDnsZoneCmd.class);
when(cmd.getName()).thenReturn("tenant.com");
when(cmd.getDnsServerId()).thenReturn(SERVER_ID);
when(dnsServerDao.findById(SERVER_ID)).thenReturn(serverVO);
Mockito.doReturn(ACCOUNT_ID + 99).when(serverVO).getAccountId(); // different owner
manager.allocateDnsZone(cmd);
}
@Test(expected = CloudRuntimeException.class)
public void testProvisionDnsZoneNotFound() {
when(dnsZoneDao.findById(ZONE_ID)).thenReturn(null);
manager.provisionDnsZone(ZONE_ID);
}
@Test
public void testProvisionDnsZoneSuccess() throws Exception {
when(dnsZoneDao.findById(ZONE_ID)).thenReturn(zoneVO);
when(dnsServerDao.findById(SERVER_ID)).thenReturn(serverVO);
when(dnsProviderMock.provisionZone(any(), any())).thenReturn("example.com.");
when(dnsZoneDao.update(anyLong(), any())).thenReturn(true);
DnsZone result = manager.provisionDnsZone(ZONE_ID);
assertNotNull(result);
verify(dnsProviderMock).provisionZone(serverVO, zoneVO);
verify(dnsZoneDao).update(anyLong(), any());
}
@Test(expected = CloudRuntimeException.class)
public void testProvisionDnsZoneConflictException() throws Exception {
when(dnsZoneDao.findById(ZONE_ID)).thenReturn(zoneVO);
when(dnsServerDao.findById(SERVER_ID)).thenReturn(serverVO);
when(dnsProviderMock.provisionZone(any(), any())).thenThrow(new DnsConflictException("conflict"));
manager.provisionDnsZone(ZONE_ID);
verify(dnsZoneDao).remove(ZONE_ID);
}
@Test(expected = CloudRuntimeException.class)
public void testProvisionDnsZoneTransportException() throws Exception {
when(dnsZoneDao.findById(ZONE_ID)).thenReturn(zoneVO);
when(dnsServerDao.findById(SERVER_ID)).thenReturn(serverVO);
when(dnsProviderMock.provisionZone(any(), any())).thenThrow(new DnsTransportException("unreachable", new IOException("i/o")));
manager.provisionDnsZone(ZONE_ID);
verify(dnsZoneDao).remove(ZONE_ID);
}
@Test(expected = InvalidParameterValueException.class)
public void testDeleteDnsZoneNotFound() {
when(dnsZoneDao.findById(ZONE_ID)).thenReturn(null);
manager.deleteDnsZone(ZONE_ID);
}
@Test(expected = CloudRuntimeException.class)
public void testDeleteDnsZoneServerMissing() {
when(dnsZoneDao.findById(ZONE_ID)).thenReturn(zoneVO);
when(dnsServerDao.findById(SERVER_ID)).thenReturn(null);
manager.deleteDnsZone(ZONE_ID);
}
@Test(expected = InvalidParameterValueException.class)
public void testUpdateDnsZoneNotFound() {
UpdateDnsZoneCmd cmd = mock(UpdateDnsZoneCmd.class);
when(cmd.getId()).thenReturn(ZONE_ID);
when(dnsZoneDao.findById(ZONE_ID)).thenReturn(null);
manager.updateDnsZone(cmd);
}
@Test
public void testUpdateDnsZoneNoChange() {
UpdateDnsZoneCmd cmd = mock(UpdateDnsZoneCmd.class);
when(cmd.getId()).thenReturn(ZONE_ID);
when(cmd.getDescription()).thenReturn(null);
when(dnsZoneDao.findById(ZONE_ID)).thenReturn(zoneVO);
DnsZone result = manager.updateDnsZone(cmd);
assertNotNull(result);
verify(dnsZoneDao, never()).update(anyLong(), any());
}
@Test
public void testUpdateDnsZoneWithDescription() throws Exception {
UpdateDnsZoneCmd cmd = mock(UpdateDnsZoneCmd.class);
when(cmd.getId()).thenReturn(ZONE_ID);
when(cmd.getDescription()).thenReturn("Updated description");
when(dnsZoneDao.findById(ZONE_ID)).thenReturn(zoneVO);
when(dnsServerDao.findById(SERVER_ID)).thenReturn(serverVO);
doNothing().when(dnsProviderMock).updateZone(any(), any());
when(dnsZoneDao.update(anyLong(), any())).thenReturn(true);
DnsZone result = manager.updateDnsZone(cmd);
assertNotNull(result);
verify(dnsProviderMock).updateZone(serverVO, zoneVO);
}
@Test(expected = CloudRuntimeException.class)
public void testUpdateDnsZoneServerMissing() {
UpdateDnsZoneCmd cmd = mock(UpdateDnsZoneCmd.class);
when(cmd.getId()).thenReturn(ZONE_ID);
when(cmd.getDescription()).thenReturn("New description");
when(dnsZoneDao.findById(ZONE_ID)).thenReturn(zoneVO);
when(dnsServerDao.findById(SERVER_ID)).thenReturn(null);
manager.updateDnsZone(cmd);
}
@Test(expected = InvalidParameterValueException.class)
public void testDeleteDnsServerNotFound() {
DeleteDnsServerCmd cmd = mock(DeleteDnsServerCmd.class);
when(cmd.getId()).thenReturn(SERVER_ID);
when(dnsServerDao.findById(SERVER_ID)).thenReturn(null);
manager.deleteDnsServer(cmd);
}
@Test
public void testDeleteDnsServerWithCleanup() throws Exception {
DeleteDnsServerCmd cmd = mock(DeleteDnsServerCmd.class);
when(cmd.getId()).thenReturn(SERVER_ID);
when(cmd.getCleanup()).thenReturn(true);
when(dnsServerDao.findById(SERVER_ID)).thenReturn(serverVO);
doNothing().when(accountMgr).checkAccess(any(Account.class), nullable(org.apache.cloudstack.acl.SecurityChecker.AccessType.class), eq(true), any());
List<DnsZoneVO> zones = Collections.singletonList(zoneVO);
when(dnsZoneDao.findDnsZonesByServerId(SERVER_ID)).thenReturn(zones);
when(dnsZoneDao.findById(ZONE_ID)).thenReturn(zoneVO);
when(dnsZoneNetworkMapDao.findByZoneId(ZONE_ID)).thenReturn(null);
when(dnsServerDao.remove(SERVER_ID)).thenReturn(true);
when(dnsZoneDao.remove(ZONE_ID)).thenReturn(true);
try (MockedStatic<Transaction> transactionMock = Mockito.mockStatic(Transaction.class)) {
transactionMock.when(() -> Transaction.execute(any(TransactionCallback.class))).thenAnswer(invocation -> {
TransactionCallback<Boolean> callback = invocation.getArgument(0);
return callback.doInTransaction(null);
});
boolean res = manager.deleteDnsServer(cmd);
assertTrue(res);
verify(dnsServerDao).remove(SERVER_ID);
verify(dnsProviderMock).deleteZone(any(), any());
}
}
@Test
public void testDeleteDnsZoneSuccess() throws Exception {
when(dnsZoneDao.findById(ZONE_ID)).thenReturn(zoneVO);
when(dnsServerDao.findById(anyLong())).thenReturn(serverVO);
doNothing().when(accountMgr).checkAccess(any(Account.class), nullable(org.apache.cloudstack.acl.SecurityChecker.AccessType.class), eq(true), any());
when(dnsZoneNetworkMapDao.findByZoneId(ZONE_ID)).thenReturn(null);
when(dnsZoneDao.remove(ZONE_ID)).thenReturn(true);
try (MockedStatic<Transaction> transactionMock = Mockito.mockStatic(Transaction.class)) {
transactionMock.when(() -> Transaction.execute(any(TransactionCallback.class))).thenAnswer(invocation -> {
TransactionCallback<Boolean> callback = invocation.getArgument(0);
return callback.doInTransaction(null);
});
boolean res = manager.deleteDnsZone(ZONE_ID);
assertTrue(res);
verify(dnsZoneDao).remove(ZONE_ID);
verify(dnsProviderMock).deleteZone(any(), any());
}
}
@Test(expected = InvalidParameterValueException.class)
public void testListDnsRecordsZoneNotFound() {
ListDnsRecordsCmd cmd = mock(ListDnsRecordsCmd.class);
when(cmd.getDnsZoneId()).thenReturn(ZONE_ID);
when(dnsZoneDao.findById(ZONE_ID)).thenReturn(null);
manager.listDnsRecords(cmd);
}
@Test(expected = CloudRuntimeException.class)
public void testListDnsRecordsServerMissing() {
ListDnsRecordsCmd cmd = mock(ListDnsRecordsCmd.class);
when(cmd.getDnsZoneId()).thenReturn(ZONE_ID);
when(dnsZoneDao.findById(ZONE_ID)).thenReturn(zoneVO);
when(dnsServerDao.findById(SERVER_ID)).thenReturn(null);
manager.listDnsRecords(cmd);
}
@Test
public void testListDnsRecordsSuccess() throws Exception {
ListDnsRecordsCmd cmd = mock(ListDnsRecordsCmd.class);
when(cmd.getDnsZoneId()).thenReturn(ZONE_ID);
when(dnsZoneDao.findById(ZONE_ID)).thenReturn(zoneVO);
when(dnsServerDao.findById(SERVER_ID)).thenReturn(serverVO);
DnsRecord record = new DnsRecord("www.example.com", DnsRecord.RecordType.A, Collections.singletonList("1.2.3.4"), 300);
when(dnsProviderMock.listRecords(any(), any())).thenReturn(Collections.singletonList(record));
ListResponse<DnsRecordResponse> result = manager.listDnsRecords(cmd);
assertNotNull(result);
assertEquals(1, result.getCount().intValue());
}
@Test(expected = CloudRuntimeException.class)
public void testListDnsRecordsZoneNotFoundInProvider() throws Exception {
ListDnsRecordsCmd cmd = mock(ListDnsRecordsCmd.class);
when(cmd.getDnsZoneId()).thenReturn(ZONE_ID);
when(dnsZoneDao.findById(ZONE_ID)).thenReturn(zoneVO);
when(dnsServerDao.findById(SERVER_ID)).thenReturn(serverVO);
when(dnsProviderMock.listRecords(any(), any())).thenThrow(new DnsNotFoundException("not found"));
manager.listDnsRecords(cmd);
}
@Test(expected = InvalidParameterValueException.class)
public void testDisassociateZoneNoMappingFound() {
DisassociateDnsZoneFromNetworkCmd cmd = mock(DisassociateDnsZoneFromNetworkCmd.class);
when(cmd.getNetworkId()).thenReturn(NETWORK_ID);
when(dnsZoneNetworkMapDao.findByNetworkId(NETWORK_ID)).thenReturn(null);
manager.disassociateZoneFromNetwork(cmd);
}
@Test
public void testDisassociateZoneOrphanedMapping() {
DisassociateDnsZoneFromNetworkCmd cmd = mock(DisassociateDnsZoneFromNetworkCmd.class);
when(cmd.getNetworkId()).thenReturn(NETWORK_ID);
DnsZoneNetworkMapVO mapping = mock(DnsZoneNetworkMapVO.class);
when(mapping.getDnsZoneId()).thenReturn(ZONE_ID);
when(mapping.getId()).thenReturn(500L);
when(dnsZoneNetworkMapDao.findByNetworkId(NETWORK_ID)).thenReturn(mapping);
when(dnsZoneDao.findById(ZONE_ID)).thenReturn(null); // zone missing (orphan)
when(dnsZoneNetworkMapDao.remove(500L)).thenReturn(true);
boolean result = manager.disassociateZoneFromNetwork(cmd);
assertTrue(result);
}
@Test
public void testDisassociateZoneSuccess() {
DisassociateDnsZoneFromNetworkCmd cmd = mock(DisassociateDnsZoneFromNetworkCmd.class);
when(cmd.getNetworkId()).thenReturn(NETWORK_ID);
DnsZoneNetworkMapVO mapping = mock(DnsZoneNetworkMapVO.class);
when(mapping.getDnsZoneId()).thenReturn(ZONE_ID);
when(mapping.getId()).thenReturn(500L);
when(dnsZoneNetworkMapDao.findByNetworkId(NETWORK_ID)).thenReturn(mapping);
when(dnsZoneDao.findById(ZONE_ID)).thenReturn(zoneVO);
when(dnsZoneNetworkMapDao.remove(500L)).thenReturn(true);
boolean result = manager.disassociateZoneFromNetwork(cmd);
assertTrue(result);
verify(dnsZoneNetworkMapDao).remove(500L);
}
@Test
public void testCreateDnsRecordResponse() {
DnsRecord record = new DnsRecord("www.example.com", DnsRecord.RecordType.A, Arrays.asList("1.2.3.4"), 300);
DnsRecordResponse response = manager.createDnsRecordResponse(record);
assertNotNull(response);
}
@Test
public void testCreateDnsServerResponseFromJoinVO() {
DnsServerJoinVO join = mock(DnsServerJoinVO.class);
when(join.getUuid()).thenReturn("uuid-1");
when(join.getName()).thenReturn("pdns");
when(join.getUrl()).thenReturn("http://pdns:8081");
when(join.getPort()).thenReturn(8081);
when(join.getProviderType()).thenReturn(DnsProviderType.PowerDNS.toString());
when(join.isPublicServer()).thenReturn(false);
when(join.getNameServers()).thenReturn(Collections.emptyList());
when(join.getPublicDomainSuffix()).thenReturn(null);
when(join.getAccountName()).thenReturn("admin");
when(join.getDomainUuid()).thenReturn("domain-uuid");
when(join.getDomainName()).thenReturn("ROOT");
when(join.getState()).thenReturn(DnsServer.State.Enabled);
DnsServerResponse response = manager.createDnsServerResponse(join);
assertNotNull(response);
}
@Test
public void testCreateDnsZoneResponseFromJoinVO() {
DnsZoneJoinVO join = mock(DnsZoneJoinVO.class);
when(join.getUuid()).thenReturn("zone-uuid");
when(join.getName()).thenReturn("example.com");
when(join.getDnsServerUuid()).thenReturn("server-uuid");
when(join.getAccountName()).thenReturn("admin");
when(join.getDomainUuid()).thenReturn("domain-uuid");
when(join.getDomainName()).thenReturn("ROOT");
when(join.getDnsServerName()).thenReturn("pdns");
when(join.getDnsServerAccountName()).thenReturn("admin");
when(join.getState()).thenReturn(DnsZone.State.Active);
when(join.getDescription()).thenReturn("Test zone");
DnsZoneResponse response = manager.createDnsZoneResponse(join);
assertNotNull(response);
}
@Test
public void testCheckDnsServerPermissionOwner() {
// owner has same accountId as server
when(callerMock.getId()).thenReturn(ACCOUNT_ID);
Mockito.doReturn(ACCOUNT_ID).when(serverVO).getAccountId();
// Should not throw
manager.checkDnsServerPermission(callerMock, serverVO);
}
@Test(expected = PermissionDeniedException.class)
public void testCheckDnsServerPermissionNonOwnerPrivate() {
when(callerMock.getId()).thenReturn(ACCOUNT_ID + 1);
Mockito.doReturn(ACCOUNT_ID).when(serverVO).getAccountId();
Mockito.doReturn(false).when(serverVO).getPublicServer();
manager.checkDnsServerPermission(callerMock, serverVO);
}
@Test(expected = PermissionDeniedException.class)
public void testCheckDnsServerPermissionNonOwnerPublicOutsideDomain() {
AccountVO serverOwner = mock(AccountVO.class);
when(callerMock.getId()).thenReturn(ACCOUNT_ID + 1);
Mockito.doReturn(ACCOUNT_ID).when(serverVO).getAccountId();
Mockito.doReturn(true).when(serverVO).getPublicServer();
when(serverOwner.getDomainId()).thenReturn(20L);
when(callerMock.getDomainId()).thenReturn(DOMAIN_ID);
ReflectionTestUtils.setField(manager, "accountDao",
Mockito.mock(com.cloud.user.dao.AccountDao.class));
com.cloud.user.dao.AccountDao accountDaoMock = (com.cloud.user.dao.AccountDao) ReflectionTestUtils.getField(manager, "accountDao");
when(accountDaoMock.findByIdIncludingRemoved(ACCOUNT_ID)).thenReturn(serverOwner);
when(domainDao.isChildDomain(20L, DOMAIN_ID)).thenReturn(false);
manager.checkDnsServerPermission(callerMock, serverVO);
}
@Test
public void testCheckDnsZonePermissionOwner() {
when(callerMock.getId()).thenReturn(ACCOUNT_ID);
Mockito.doReturn(ACCOUNT_ID).when(zoneVO).getAccountId();
// Should not throw
manager.checkDnsZonePermission(callerMock, zoneVO);
}
@Test(expected = PermissionDeniedException.class)
public void testCheckDnsZonePermissionNonOwner() {
when(callerMock.getId()).thenReturn(ACCOUNT_ID + 1);
Mockito.doReturn(ACCOUNT_ID).when(zoneVO).getAccountId();
manager.checkDnsZonePermission(callerMock, zoneVO);
}
@Test
public void testAddDnsRecordForVMNoNetworkMapping() throws DnsProviderException {
Network network = mock(Network.class);
NicVO nic = mock(NicVO.class);
VMInstanceVO vm = mock(VMInstanceVO.class);
when(dnsZoneNetworkMapDao.findByNetworkId(anyLong())).thenReturn(null);
when(network.getId()).thenReturn(NETWORK_ID);
manager.addDnsRecordForVM(vm, network, nic);
verify(dnsProviderMock, never()).addRecord(any(), any(), any());
}
@Test
public void testAddDnsRecordForVMInactiveZone() {
Network network = mock(Network.class);
NicVO nic = mock(NicVO.class);
VMInstanceVO vm = mock(VMInstanceVO.class);
DnsZoneNetworkMapVO mapping = mock(DnsZoneNetworkMapVO.class);
when(network.getId()).thenReturn(NETWORK_ID);
when(dnsZoneNetworkMapDao.findByNetworkId(NETWORK_ID)).thenReturn(mapping);
when(mapping.getDnsZoneId()).thenReturn(ZONE_ID);
DnsZoneVO inactiveZone = Mockito.spy(new DnsZoneVO("ex.com", DnsZone.ZoneType.Public, SERVER_ID, ACCOUNT_ID, DOMAIN_ID, ""));
// state defaults to Inactive
when(dnsZoneDao.findById(ZONE_ID)).thenReturn(inactiveZone);
manager.addDnsRecordForVM(vm, network, nic);
verify(dnsServerDao, never()).findById(anyLong());
}
@Test
public void testAddDnsRecordForVMServerMissing() {
Network network = mock(Network.class);
NicVO nic = mock(NicVO.class);
VMInstanceVO vm = mock(VMInstanceVO.class);
DnsZoneNetworkMapVO mapping = mock(DnsZoneNetworkMapVO.class);
when(network.getId()).thenReturn(NETWORK_ID);
when(dnsZoneNetworkMapDao.findByNetworkId(NETWORK_ID)).thenReturn(mapping);
when(mapping.getDnsZoneId()).thenReturn(ZONE_ID);
DnsZoneVO activeZone = Mockito.spy(new DnsZoneVO("ex.com", DnsZone.ZoneType.Public, SERVER_ID, ACCOUNT_ID, DOMAIN_ID, ""));
activeZone.setState(DnsZone.State.Active);
when(dnsZoneDao.findById(ZONE_ID)).thenReturn(activeZone);
when(dnsServerDao.findById(SERVER_ID)).thenReturn(null);
when(vm.getInstanceName()).thenReturn("vm-1");
manager.addDnsRecordForVM(vm, network, nic);
verify(nicDetailsDao, never()).addDetail(anyLong(), anyString(), anyString(), eq(true));
}
@Test
public void testDeleteDnsRecordForVMNoNicDetail() {
Network network = mock(Network.class);
NicVO nic = mock(NicVO.class);
VMInstanceVO vm = mock(VMInstanceVO.class);
when(nic.getId()).thenReturn(50L);
when(vm.getInstanceName()).thenReturn("vm-1");
when(nicDetailsDao.findDetail(50L, "nicdnsrecord")).thenReturn(null);
manager.deleteDnsRecordForVM(vm, network, nic);
verify(dnsZoneNetworkMapDao, never()).findByNetworkId(anyLong());
}
@Test
public void testDeleteDnsRecordForVMNicDetailBlankValue() {
Network network = mock(Network.class);
NicVO nic = mock(NicVO.class);
VMInstanceVO vm = mock(VMInstanceVO.class);
NicDetailVO detail = mock(NicDetailVO.class);
when(nic.getId()).thenReturn(50L);
when(vm.getInstanceName()).thenReturn("vm-1");
when(nicDetailsDao.findDetail(50L, "nicdnsrecord")).thenReturn(detail);
when(detail.getValue()).thenReturn(" ");
manager.deleteDnsRecordForVM(vm, network, nic);
verify(dnsZoneNetworkMapDao, never()).findByNetworkId(anyLong());
}
@Test
public void testProcessEventForDnsRecordAdd() throws Exception {
Network network = mock(Network.class);
NicVO nic = mock(NicVO.class);
VMInstanceVO vm = mock(VMInstanceVO.class);
when(dnsZoneNetworkMapDao.findByNetworkId(anyLong())).thenReturn(null);
when(network.getId()).thenReturn(NETWORK_ID);
manager.processEventForDnsRecord(vm, network, nic, true);
// addDnsRecordForVM was called returns early because no mapping
verify(dnsZoneNetworkMapDao, times(1)).findByNetworkId(NETWORK_ID);
}
@Test
public void testProcessEventForDnsRecordDelete() {
Network network = mock(Network.class);
NicVO nic = mock(NicVO.class);
VMInstanceVO vm = mock(VMInstanceVO.class);
when(nic.getId()).thenReturn(50L);
when(vm.getInstanceName()).thenReturn("vm-1");
when(nicDetailsDao.findDetail(50L, "nicdnsrecord")).thenReturn(null);
manager.processEventForDnsRecord(vm, network, nic, false);
verify(nicDetailsDao, times(1)).findDetail(50L, "nicdnsrecord");
}
@Test
public void testGetCommandsReturnsNonEmptyList() {
List<Class<?>> commands = manager.getCommands();
assertNotNull(commands);
assertFalse(commands.isEmpty());
assertTrue(commands.size() > 5);
}
@Test
public void testStartWithNoProviders() {
manager.setDnsProviders(Collections.emptyList());
assertTrue(manager.start());
}
@Test
public void testStartWithProviders() {
assertTrue(manager.start());
}
@Test(expected = InvalidParameterValueException.class)
public void testAssociateZoneToNetworkZoneNotFound() {
org.apache.cloudstack.api.command.user.dns.AssociateDnsZoneToNetworkCmd cmd =
mock(org.apache.cloudstack.api.command.user.dns.AssociateDnsZoneToNetworkCmd.class);
when(cmd.getDnsZoneId()).thenReturn(ZONE_ID);
when(dnsZoneDao.findById(ZONE_ID)).thenReturn(null);
manager.associateZoneToNetwork(cmd);
}
@Test(expected = InvalidParameterValueException.class)
public void testAssociateZoneToNetworkNetworkNotFound() {
org.apache.cloudstack.api.command.user.dns.AssociateDnsZoneToNetworkCmd cmd =
mock(org.apache.cloudstack.api.command.user.dns.AssociateDnsZoneToNetworkCmd.class);
when(cmd.getDnsZoneId()).thenReturn(ZONE_ID);
when(cmd.getNetworkId()).thenReturn(NETWORK_ID);
when(dnsZoneDao.findById(ZONE_ID)).thenReturn(zoneVO);
when(dnsServerDao.findById(SERVER_ID)).thenReturn(serverVO);
when(networkDao.findById(NETWORK_ID)).thenReturn(null);
manager.associateZoneToNetwork(cmd);
}
@Test(expected = CloudRuntimeException.class)
public void testAssociateZoneToNetworkNonSharedNetwork() {
org.apache.cloudstack.api.command.user.dns.AssociateDnsZoneToNetworkCmd cmd =
mock(org.apache.cloudstack.api.command.user.dns.AssociateDnsZoneToNetworkCmd.class);
when(cmd.getDnsZoneId()).thenReturn(ZONE_ID);
when(cmd.getNetworkId()).thenReturn(NETWORK_ID);
when(dnsZoneDao.findById(ZONE_ID)).thenReturn(zoneVO);
when(dnsServerDao.findById(SERVER_ID)).thenReturn(serverVO);
NetworkVO network = mock(NetworkVO.class);
when(network.getGuestType()).thenReturn(NetworkVO.GuestType.Isolated);
when(networkDao.findById(NETWORK_ID)).thenReturn(network);
manager.associateZoneToNetwork(cmd);
}
@Test
public void testAssociateZoneToNetworkSuccess() {
org.apache.cloudstack.api.command.user.dns.AssociateDnsZoneToNetworkCmd cmd =
mock(org.apache.cloudstack.api.command.user.dns.AssociateDnsZoneToNetworkCmd.class);
when(cmd.getDnsZoneId()).thenReturn(ZONE_ID);
when(cmd.getNetworkId()).thenReturn(NETWORK_ID);
when(dnsZoneDao.findById(ZONE_ID)).thenReturn(zoneVO);
Mockito.doReturn("zone-uuid").when(zoneVO).getUuid();
when(dnsServerDao.findById(SERVER_ID)).thenReturn(serverVO);
NetworkVO network = mock(NetworkVO.class);
when(network.getGuestType()).thenReturn(NetworkVO.GuestType.Shared);
when(networkDao.findById(NETWORK_ID)).thenReturn(network);
DnsZoneNetworkMapVO savedMapping = mock(DnsZoneNetworkMapVO.class);
when(dnsZoneNetworkMapDao.persist(any(DnsZoneNetworkMapVO.class))).thenReturn(savedMapping);
DnsZoneNetworkMapResponse response = manager.associateZoneToNetwork(cmd);
assertNotNull(response);
verify(dnsZoneNetworkMapDao).persist(any(DnsZoneNetworkMapVO.class));
}
@Test(expected = InvalidParameterValueException.class)
public void testAssociateZoneToNetworkAlreadyAssociated() {
org.apache.cloudstack.api.command.user.dns.AssociateDnsZoneToNetworkCmd cmd =
mock(org.apache.cloudstack.api.command.user.dns.AssociateDnsZoneToNetworkCmd.class);
when(cmd.getDnsZoneId()).thenReturn(ZONE_ID);
when(cmd.getNetworkId()).thenReturn(NETWORK_ID);
when(dnsZoneDao.findById(ZONE_ID)).thenReturn(zoneVO);
when(dnsServerDao.findById(SERVER_ID)).thenReturn(serverVO);
NetworkVO network = mock(NetworkVO.class);
when(network.getGuestType()).thenReturn(NetworkVO.GuestType.Shared);
when(network.getId()).thenReturn(NETWORK_ID);
when(networkDao.findById(NETWORK_ID)).thenReturn(network);
when(dnsZoneNetworkMapDao.findByNetworkId(NETWORK_ID)).thenReturn(mock(DnsZoneNetworkMapVO.class));
manager.associateZoneToNetwork(cmd);
}
@Test
public void testCreateDnsRecordSuccess() throws Exception {
org.apache.cloudstack.api.command.user.dns.CreateDnsRecordCmd cmd = mock(org.apache.cloudstack.api.command.user.dns.CreateDnsRecordCmd.class);
when(cmd.getName()).thenReturn("www");
when(cmd.getDnsZoneId()).thenReturn(ZONE_ID);
when(cmd.getType()).thenReturn(DnsRecord.RecordType.A);
when(cmd.getContents()).thenReturn(Collections.singletonList("1.2.3.4"));
when(dnsZoneDao.findById(ZONE_ID)).thenReturn(zoneVO);
when(dnsServerDao.findById(anyLong())).thenReturn(serverVO);
when(dnsProviderMock.addRecord(any(), any(), any())).thenReturn("www.example.com");
DnsRecordResponse res = manager.createDnsRecord(cmd);
assertNotNull(res);
verify(dnsProviderMock).addRecord(any(), any(), any());
}
@Test
public void testDeleteDnsRecordSuccess() throws Exception {
org.apache.cloudstack.api.command.user.dns.DeleteDnsRecordCmd cmd = mock(org.apache.cloudstack.api.command.user.dns.DeleteDnsRecordCmd.class);
when(cmd.getDnsZoneId()).thenReturn(ZONE_ID);
when(cmd.getName()).thenReturn("www");
when(dnsZoneDao.findById(ZONE_ID)).thenReturn(zoneVO);
when(dnsServerDao.findById(anyLong())).thenReturn(serverVO);
when(dnsProviderMock.deleteRecord(any(), any(), any())).thenReturn("www.example.com");
boolean res = manager.deleteDnsRecord(cmd);
assertTrue(res);
verify(dnsProviderMock).deleteRecord(any(), any(), any());
}
@Test
public void testDeleteDnsRecordForVMSuccess() throws Exception {
Network network = mock(Network.class);
NicVO nic = mock(NicVO.class);
when(nic.getIPv4Address()).thenReturn("1.2.3.4");
VMInstanceVO vm = mock(VMInstanceVO.class);
NicDetailVO detail = mock(NicDetailVO.class);
when(nic.getId()).thenReturn(50L);
when(vm.getInstanceName()).thenReturn("vm-1");
when(nicDetailsDao.findDetail(50L, "nicdnsrecord")).thenReturn(detail);
when(detail.getValue()).thenReturn("vm-1.ex.com");
DnsZoneNetworkMapVO mapping = mock(DnsZoneNetworkMapVO.class);
when(network.getId()).thenReturn(NETWORK_ID);
when(dnsZoneNetworkMapDao.findByNetworkId(NETWORK_ID)).thenReturn(mapping);
when(mapping.getDnsZoneId()).thenReturn(ZONE_ID);
when(dnsZoneDao.findById(ZONE_ID)).thenReturn(zoneVO);
when(dnsServerDao.findById(anyLong())).thenReturn(serverVO);
when(dnsProviderMock.deleteRecord(any(), any(), any())).thenReturn("vm-1.ex.com");
manager.deleteDnsRecordForVM(vm, network, nic);
verify(dnsProviderMock).deleteRecord(any(), any(), any());
verify(nicDetailsDao).removeDetail(50L, "nicdnsrecord");
}
@Test
public void testConfigure() throws Exception {
assertTrue(manager.configure("dnsProviderManagerImpl", Collections.emptyMap()));
verify(messageBus, times(3)).subscribe(anyString(), any());
}
@Test
public void testHandleVmEventAndNicEvent() throws Exception {
VMInstanceVO vm = mock(VMInstanceVO.class);
NicVO nic = mock(NicVO.class);
NetworkVO network = mock(NetworkVO.class);
when(network.getId()).thenReturn(NETWORK_ID);
when(vmInstanceDao.findById(10L)).thenReturn(vm);
when(nicDao.findByIdIncludingRemoved(50L)).thenReturn(nic);
when(nic.getNetworkId()).thenReturn(NETWORK_ID);
when(networkDao.findById(NETWORK_ID)).thenReturn(network);
when(network.getGuestType()).thenReturn(Network.GuestType.Shared);
when(dnsZoneNetworkMapDao.findByNetworkId(NETWORK_ID)).thenReturn(null);
org.springframework.test.util.ReflectionTestUtils.invokeMethod(manager, "handleNicEvent", 50L, 10L, true);
verify(dnsZoneNetworkMapDao, times(1)).findByNetworkId(NETWORK_ID);
when(vmInstanceDao.findByIdIncludingRemoved(10L)).thenReturn(vm);
when(vm.getId()).thenReturn(10L);
when(nicDao.listByVmIdIncludingRemoved(10L)).thenReturn(Collections.singletonList(nic));
org.springframework.test.util.ReflectionTestUtils.invokeMethod(manager, "handleVmEvent", 10L, true);
verify(dnsZoneNetworkMapDao, times(2)).findByNetworkId(NETWORK_ID);
}
@Test
public void testAddDnsServerSuccess() throws Exception {
org.apache.cloudstack.api.command.user.dns.AddDnsServerCmd cmd = mock(org.apache.cloudstack.api.command.user.dns.AddDnsServerCmd.class);
when(callerMock.getType()).thenReturn(Account.Type.ADMIN);
when(cmd.getUrl()).thenReturn("http://newpdns:8081");
when(cmd.getProvider()).thenReturn(DnsProviderType.PowerDNS);
when(dnsServerDao.findByUrlAndAccount(anyString(), anyLong())).thenReturn(null);
when(dnsProviderMock.validateAndResolveServer(any())).thenReturn("resolved-id");
when(dnsServerDao.persist(any())).thenReturn(serverVO);
DnsServer result = manager.addDnsServer(cmd);
assertNotNull(result);
verify(dnsServerDao).persist(any());
}
@Test
public void testListDnsServers() {
org.apache.cloudstack.api.command.user.dns.ListDnsServersCmd cmd = mock(org.apache.cloudstack.api.command.user.dns.ListDnsServersCmd.class);
when(domainDao.getDomainParentIds(anyLong())).thenReturn(Collections.emptySet());
List<DnsServerVO> servers = Collections.singletonList(serverVO);
com.cloud.utils.Pair<List<DnsServerVO>, Integer> searchPair = new com.cloud.utils.Pair<>(servers, 1);
when(dnsServerDao.searchDnsServer(any(), anyLong(), any(), any(), any(), any())).thenReturn(searchPair);
DnsServerJoinVO joinVO = mock(DnsServerJoinVO.class);
when(joinVO.getProviderType()).thenReturn(DnsProviderType.PowerDNS.toString());
when(joinVO.getState()).thenReturn(DnsServer.State.Enabled);
when(dnsServerJoinDao.listByUuids(any())).thenReturn(Collections.singletonList(joinVO));
ListResponse<DnsServerResponse> res = manager.listDnsServers(cmd);
assertEquals(1, res.getCount().intValue());
}
@Test
public void testUpdateDnsServer() throws Exception {
org.apache.cloudstack.api.command.user.dns.UpdateDnsServerCmd cmd = mock(org.apache.cloudstack.api.command.user.dns.UpdateDnsServerCmd.class);
when(cmd.getId()).thenReturn(SERVER_ID);
when(cmd.getName()).thenReturn("updated-name");
when(dnsServerDao.findById(SERVER_ID)).thenReturn(serverVO);
when(dnsServerDao.update(eq(SERVER_ID), any())).thenReturn(true);
DnsServer res = manager.updateDnsServer(cmd);
assertNotNull(res);
verify(dnsServerDao).update(eq(SERVER_ID), any());
}
@Test
public void testListDnsZones() {
org.apache.cloudstack.api.command.user.dns.ListDnsZonesCmd cmd = mock(org.apache.cloudstack.api.command.user.dns.ListDnsZonesCmd.class);
when(cmd.getId()).thenReturn(null);
when(dnsServerDao.listDnsServerIdsByAccountId(anyLong())).thenReturn(Collections.emptyList());
List<DnsZoneVO> zones = Collections.singletonList(zoneVO);
com.cloud.utils.Pair<List<DnsZoneVO>, Integer> searchPair = new com.cloud.utils.Pair<>(zones, 1);
when(dnsZoneDao.searchZones(any(), anyLong(), any(), any(), any(), any())).thenReturn(searchPair);
DnsZoneJoinVO joinVO = mock(DnsZoneJoinVO.class);
when(dnsZoneJoinDao.listByUuids(any())).thenReturn(Collections.singletonList(joinVO));
ListResponse<DnsZoneResponse> res = manager.listDnsZones(cmd);
assertEquals(1, res.getCount().intValue());
}
}

View File

@ -0,0 +1,91 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.dns;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class DnsProviderUtilTest {
@Test
public void testNormalizeDnsRecordValueA() {
String result = DnsProviderUtil.normalizeDnsRecordValue(" 1.2.3.4 ", DnsRecord.RecordType.A);
assertEquals("1.2.3.4", result);
}
@Test
public void testNormalizeDnsRecordValueAAAA() {
String result = DnsProviderUtil.normalizeDnsRecordValue(" 2001:db8::1 ", DnsRecord.RecordType.AAAA);
assertEquals("2001:db8::1", result);
}
@Test
public void testNormalizeDnsRecordValueCNAME() {
// Appends dot in the process? No, normalizeDomain trims, lowercases, removes trailing dot, and checks validity.
String result = DnsProviderUtil.normalizeDnsRecordValue(" Host.Example.Com. ", DnsRecord.RecordType.CNAME);
assertEquals("host.example.com", result);
}
@Test
public void testNormalizeDnsRecordValueNS() {
String result = DnsProviderUtil.normalizeDnsRecordValue("NS1.EXAMPLE.COM", DnsRecord.RecordType.NS);
assertEquals("ns1.example.com", result);
}
@Test
public void testNormalizeDnsRecordValuePTR() {
String result = DnsProviderUtil.normalizeDnsRecordValue("ptr.valid.zone.", DnsRecord.RecordType.PTR);
assertEquals("ptr.valid.zone", result);
}
@Test
public void testNormalizeDnsRecordValueSRV() {
String result = DnsProviderUtil.normalizeDnsRecordValue("srv.example.com", DnsRecord.RecordType.SRV);
assertEquals("srv.example.com", result);
}
@Test
public void testNormalizeDnsRecordValueMX() {
// MX records just get trimmed and lowercased
String result = DnsProviderUtil.normalizeDnsRecordValue(" 10 MAIL.EXAMPLE.COM ", DnsRecord.RecordType.MX);
assertEquals("10 mail.example.com", result);
}
@Test
public void testNormalizeDnsRecordValueTXT() {
// TXT records are preserved exactly
String result = DnsProviderUtil.normalizeDnsRecordValue(" Exact text value. ", DnsRecord.RecordType.TXT);
assertEquals(" Exact text value. ", result);
}
@Test(expected = IllegalArgumentException.class)
public void testNormalizeDnsRecordValueEmpty() {
DnsProviderUtil.normalizeDnsRecordValue(" ", DnsRecord.RecordType.A);
}
@Test(expected = IllegalArgumentException.class)
public void testNormalizeDnsRecordValueNull() {
DnsProviderUtil.normalizeDnsRecordValue(null, DnsRecord.RecordType.A);
}
@Test(expected = IllegalArgumentException.class)
public void testNormalizeDnsRecordValueInvalidDomain() {
DnsProviderUtil.normalizeDnsRecordValue("invalid!domain", DnsRecord.RecordType.CNAME);
}
}

View File

@ -0,0 +1,117 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.dns.dao;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.cloudstack.dns.DnsProviderType;
import org.apache.cloudstack.dns.DnsServer;
import org.apache.cloudstack.dns.vo.DnsServerVO;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
import com.cloud.utils.Pair;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.SearchCriteria;
@RunWith(MockitoJUnitRunner.class)
public class DnsServerDaoImplTest {
DnsServerDaoImpl dao;
DnsServerVO mockServer;
@Before
public void setUp() {
dao = spy(new DnsServerDaoImpl());
mockServer = new DnsServerVO("test-server", "http://pdns:8081", 8081, "localhost", DnsProviderType.PowerDNS, null, "apikey", false, null, Collections.singletonList("ns1.example.com"), 1L, 10L);
}
@Test
public void testFindByUrlAndAccount() {
doReturn(mockServer).when(dao).findOneBy(any(SearchCriteria.class));
DnsServer result = dao.findByUrlAndAccount("http://pdns:8081", 1L);
assertNotNull(result);
assertEquals("test-server", result.getName());
assertEquals("http://pdns:8081", result.getUrl());
}
@Test
public void testListDnsServerIdsByAccountId() {
List<Long> expectedIds = Arrays.asList(100L);
doReturn(expectedIds).when(dao).customSearch(any(SearchCriteria.class), any());
List<Long> result = dao.listDnsServerIdsByAccountId(1L);
assertNotNull(result);
assertEquals(1, result.size());
assertEquals(100L, result.get(0).longValue());
}
@Test
public void testListDnsServerIdsByAccountIdNullAccount() {
List<Long> expectedIds = Arrays.asList(100L, 200L);
doReturn(expectedIds).when(dao).customSearch(any(SearchCriteria.class), any());
List<Long> result = dao.listDnsServerIdsByAccountId(null);
assertNotNull(result);
assertEquals(2, result.size());
}
@Test
public void testSearchDnsServerWithAllParams() {
List<DnsServerVO> expected = Collections.singletonList(mockServer);
Pair<List<DnsServerVO>, Integer> expectedPair = new Pair<>(expected, 1);
doReturn(expectedPair).when(dao).searchAndCount(any(SearchCriteria.class), any());
Filter filter = new Filter(DnsServerVO.class, "id", true, 0L, 10L);
Set<Long> domainIds = new HashSet<>(Arrays.asList(10L, 20L));
Pair<List<DnsServerVO>, Integer> result = dao.searchDnsServer(100L, 1L, domainIds, DnsProviderType.PowerDNS, "test", filter);
assertNotNull(result);
assertEquals(1, result.first().size());
assertEquals(1, result.second().intValue());
assertEquals("test-server", result.first().get(0).getName());
}
@Test
public void testSearchDnsServerWithNullParams() {
List<DnsServerVO> expected = Collections.singletonList(mockServer);
Pair<List<DnsServerVO>, Integer> expectedPair = new Pair<>(expected, 1);
doReturn(expectedPair).when(dao).searchAndCount(any(SearchCriteria.class), any());
Filter filter = new Filter(DnsServerVO.class, "id", true, 0L, 10L);
Set<Long> domainIds = new HashSet<>();
Pair<List<DnsServerVO>, Integer> result = dao.searchDnsServer(null, null, domainIds, null, null, filter);
assertNotNull(result);
assertEquals(1, result.first().size());
assertEquals(1, result.second().intValue());
}
}

View File

@ -0,0 +1,111 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.dns.dao;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.apache.cloudstack.dns.DnsZone;
import org.apache.cloudstack.dns.vo.DnsZoneVO;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
import com.cloud.utils.Pair;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.SearchCriteria;
@RunWith(MockitoJUnitRunner.class)
public class DnsZoneDaoImplTest {
DnsZoneDaoImpl dao;
DnsZoneVO mockZone;
@Before
public void setUp() {
dao = spy(new DnsZoneDaoImpl());
mockZone = new DnsZoneVO("example.com", DnsZone.ZoneType.Public, 1L, 10L, 100L, "test zone");
}
@Test
public void testListByAccount() {
List<DnsZoneVO> expected = Collections.singletonList(mockZone);
doReturn(expected).when(dao).listBy(any(SearchCriteria.class));
List<DnsZoneVO> result = dao.listByAccount(10L);
assertEquals(1, result.size());
assertEquals("example.com", result.get(0).getName());
}
@Test
public void testFindByNameServerAndType() {
doReturn(mockZone).when(dao).findOneBy(any(SearchCriteria.class));
DnsZoneVO result = dao.findByNameServerAndType("example.com", 1L, DnsZone.ZoneType.Public);
assertNotNull(result);
assertEquals("example.com", result.getName());
}
@Test
public void testFindDnsZonesByServerId() {
List<DnsZoneVO> expected = Collections.singletonList(mockZone);
doReturn(expected).when(dao).listBy(any(SearchCriteria.class));
List<DnsZoneVO> result = dao.findDnsZonesByServerId(1L);
assertEquals(1, result.size());
}
@Test
public void testSearchZonesWithAllParams() {
List<DnsZoneVO> expected = Collections.singletonList(mockZone);
Pair<List<DnsZoneVO>, Integer> expectedPair = new Pair<>(expected, 1);
doReturn(expectedPair).when(dao).searchAndCount(any(SearchCriteria.class), any());
Filter filter = new Filter(DnsZoneVO.class, "id", true, 0L, 10L);
List<Long> ownDnsServerIds = Arrays.asList(1L, 2L);
Pair<List<DnsZoneVO>, Integer> result = dao.searchZones(1L, 10L, ownDnsServerIds, 1L, "example", filter);
assertNotNull(result);
assertEquals(1, result.first().size());
assertEquals(1, result.second().intValue());
}
@Test
public void testSearchZonesWithNullParams() {
List<DnsZoneVO> expected = Collections.singletonList(mockZone);
Pair<List<DnsZoneVO>, Integer> expectedPair = new Pair<>(expected, 1);
doReturn(expectedPair).when(dao).searchAndCount(any(SearchCriteria.class), any());
Filter filter = new Filter(DnsZoneVO.class, "id", true, 0L, 10L);
List<Long> ownDnsServerIds = new ArrayList<>();
Pair<List<DnsZoneVO>, Integer> result = dao.searchZones(null, null, ownDnsServerIds, null, null, filter);
assertNotNull(result);
assertEquals(1, result.first().size());
assertEquals(1, result.second().intValue());
}
}