diff --git a/pom.xml b/pom.xml index 7ad6f3faa..4dc15fd8c 100644 --- a/pom.xml +++ b/pom.xml @@ -801,6 +801,30 @@ ${version.wiremock} test + + com.squareup.okhttp3 + mockwebserver + 4.10.0 + test + + + io.projectreactor + reactor-test + 3.6.0 + test + + + org.springframework + spring-test + 5.3.29 + test + + + org.springframework.boot + spring-boot-starter-test + ${version.spring-webflux} + test + com.fasterxml.jackson.core jackson-annotations diff --git a/rest-mvc/pom.xml b/rest-mvc/pom.xml index 09b6c8fc9..50a9c5419 100644 --- a/rest-mvc/pom.xml +++ b/rest-mvc/pom.xml @@ -59,6 +59,31 @@ tank-script-processor ${project.version} + + com.squareup.okhttp3 + mockwebserver + test + + + org.wiremock + wiremock + test + + + io.projectreactor + reactor-test + test + + + org.springframework + spring-test + test + + + org.springframework.boot + spring-boot-starter-test + test + diff --git a/rest-mvc/src/main/java/com/intuit/tank/rest/mvc/rest/clients/AgentClient.java b/rest-mvc/src/main/java/com/intuit/tank/rest/mvc/rest/clients/AgentClient.java index d2f9173c8..e774ca787 100644 --- a/rest-mvc/src/main/java/com/intuit/tank/rest/mvc/rest/clients/AgentClient.java +++ b/rest-mvc/src/main/java/com/intuit/tank/rest/mvc/rest/clients/AgentClient.java @@ -20,8 +20,6 @@ import org.springframework.http.MediaType; import reactor.core.publisher.Mono; -import java.util.Map; - public class AgentClient extends BaseClient{ private static final String SERVICE_BASE_URL = "/v2/agent"; @@ -44,7 +42,7 @@ public String getSettings() { .uri(urlBuilder.buildUrl("/settings")) .accept(MediaType.APPLICATION_XML) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -57,7 +55,7 @@ public Mono getSupportFiles() { .uri(urlBuilder.buildUrl("/support-files")) .accept(MediaType.APPLICATION_OCTET_STREAM) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -71,7 +69,7 @@ public AgentTestStartData agentReady(AgentData agentData) { .accept(MediaType.APPLICATION_JSON) .body(Mono.just(agentData), AgentData.class) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -84,7 +82,7 @@ public Headers getHeaders() { .uri(urlBuilder.buildUrl("/headers")) .accept(MediaType.APPLICATION_XML) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -97,7 +95,7 @@ public TankHttpClientDefinitionContainer getClients() { .uri(urlBuilder.buildUrl("/clients")) .accept(MediaType.APPLICATION_XML) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -111,7 +109,7 @@ public Void setStandaloneAgentAvailability(AgentAvailability availability) { .contentType(MediaType.APPLICATION_JSON) .body(Mono.just(availability), AgentAvailability.class) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -124,7 +122,7 @@ public CloudVmStatus getInstanceStatus(String instanceId) { .uri(urlBuilder.buildUrl("/instance/status/", instanceId)) .accept(MediaType.APPLICATION_JSON) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -138,7 +136,7 @@ public Void setInstanceStatus(String instanceId, CloudVmStatus VmStatus) { .contentType(MediaType.APPLICATION_JSON) .body(Mono.just(VmStatus), CloudVmStatus.class) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -146,12 +144,14 @@ public Void setInstanceStatus(String instanceId, CloudVmStatus VmStatus) { .block(); } + // Instance Actions + public String stopInstance(String instanceId) { return client.get() .uri(urlBuilder.buildUrl("/instance/stop/", instanceId)) .accept(MediaType.TEXT_PLAIN) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -164,7 +164,7 @@ public String pauseInstance(String instanceId) { .uri(urlBuilder.buildUrl("/instance/pause/", instanceId)) .accept(MediaType.TEXT_PLAIN) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -177,7 +177,7 @@ public String resumeInstance(String instanceId) { .uri(urlBuilder.buildUrl("/instance/resume/", instanceId)) .accept(MediaType.TEXT_PLAIN) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -190,7 +190,7 @@ public String killInstance(String instanceId) { .uri(urlBuilder.buildUrl("/instance/kill/", instanceId)) .accept(MediaType.TEXT_PLAIN) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) diff --git a/rest-mvc/src/main/java/com/intuit/tank/rest/mvc/rest/clients/BaseClient.java b/rest-mvc/src/main/java/com/intuit/tank/rest/mvc/rest/clients/BaseClient.java index 15e3b8195..2f96abf91 100644 --- a/rest-mvc/src/main/java/com/intuit/tank/rest/mvc/rest/clients/BaseClient.java +++ b/rest-mvc/src/main/java/com/intuit/tank/rest/mvc/rest/clients/BaseClient.java @@ -76,7 +76,7 @@ public String ping() { .uri(urlBuilder.buildUrl("/ping")) .accept(MediaType.TEXT_PLAIN) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) diff --git a/rest-mvc/src/main/java/com/intuit/tank/rest/mvc/rest/clients/DataFileClient.java b/rest-mvc/src/main/java/com/intuit/tank/rest/mvc/rest/clients/DataFileClient.java index 2093de274..ca0905580 100644 --- a/rest-mvc/src/main/java/com/intuit/tank/rest/mvc/rest/clients/DataFileClient.java +++ b/rest-mvc/src/main/java/com/intuit/tank/rest/mvc/rest/clients/DataFileClient.java @@ -14,6 +14,12 @@ import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.multipart.MultipartFile; import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.web.reactive.function.BodyInserters; +import org.springframework.http.ResponseEntity; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpStatus; +import org.springframework.util.MultiValueMap; +import org.springframework.util.LinkedMultiValueMap; import org.springframework.http.MediaType; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -43,7 +49,7 @@ public DataFileDescriptorContainer getDatafiles() { .uri(baseUrl) .accept(MediaType.APPLICATION_JSON) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -56,7 +62,7 @@ public DataFileDescriptor getDatafile(Integer datafileId) { .uri(urlBuilder.buildUrl("", datafileId)) .accept(MediaType.APPLICATION_JSON) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -71,7 +77,7 @@ public String getDatafileContent(Integer datafileId) { .queryParam("id", datafileId.toString()) .build()) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -90,29 +96,30 @@ public Mono downloadDatafile(Integer datafileId) { .uri(urlBuilder.buildUrl("/download", datafileId)) .accept(MediaType.APPLICATION_OCTET_STREAM) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) .bodyToMono(DataBuffer.class); } - public Map uploadDatafile(Integer id, MultipartFile file) { - return client.post() - .uri(uriBuilder -> uriBuilder - .path(urlBuilder.buildUrl("/upload")) + public Mono>> uploadDatafile(Integer id, MultipartFile file) { + MultiValueMap formData = new LinkedMultiValueMap<>(); + formData.add("file", file.getResource()); + + return WebClient.create(urlBuilder.buildUrl("")) + .post() + .uri(uriBuilder -> uriBuilder.path("/upload") .queryParam("id", id) .build()) .contentType(MediaType.MULTIPART_FORM_DATA) - .accept(MediaType.APPLICATION_JSON) - .body(Mono.just(file), MultipartFile.class) + .body(BodyInserters.fromMultipartData(formData)) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) - .bodyToMono(Map.class) - .block(); + .toEntity(new ParameterizedTypeReference<>() {}); } public String deleteDatafile(Integer datafileID) { @@ -120,7 +127,7 @@ public String deleteDatafile(Integer datafileID) { .uri(urlBuilder.buildUrl("", datafileID)) .accept(MediaType.TEXT_PLAIN) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) diff --git a/rest-mvc/src/main/java/com/intuit/tank/rest/mvc/rest/clients/FilterClient.java b/rest-mvc/src/main/java/com/intuit/tank/rest/mvc/rest/clients/FilterClient.java index 3280f8477..53d7b4ef3 100644 --- a/rest-mvc/src/main/java/com/intuit/tank/rest/mvc/rest/clients/FilterClient.java +++ b/rest-mvc/src/main/java/com/intuit/tank/rest/mvc/rest/clients/FilterClient.java @@ -9,6 +9,7 @@ import com.intuit.tank.rest.mvc.rest.clients.util.ClientException; import com.intuit.tank.rest.mvc.rest.models.filters.*; +import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import reactor.core.publisher.Mono; @@ -36,7 +37,7 @@ public FilterContainer getFilters() { .uri(baseUrl) .accept(MediaType.APPLICATION_JSON) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -49,7 +50,7 @@ public FilterGroupContainer getFilterGroups() { .uri(urlBuilder.buildUrl("/groups")) .accept(MediaType.APPLICATION_JSON) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -62,7 +63,7 @@ public FilterTO getFilter(Integer filterId) { .uri(urlBuilder.buildUrl("", filterId)) .accept(MediaType.APPLICATION_JSON) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -75,7 +76,7 @@ public FilterGroupTO getFilterGroup(Integer filterGroupId) { .uri(urlBuilder.buildUrl("", filterGroupId)) .accept(MediaType.APPLICATION_JSON) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -90,7 +91,7 @@ public String applyFilters(Integer scriptId, ApplyFiltersRequest request) { .accept(MediaType.TEXT_PLAIN) .body(Mono.just(request), ApplyFiltersRequest.class) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -103,7 +104,7 @@ public String deleteFilter(Integer filterId) { .uri(urlBuilder.buildUrl("", filterId)) .accept(MediaType.TEXT_PLAIN) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -116,7 +117,7 @@ public String deleteFilterGroup(Integer filterGroupId) { .uri(urlBuilder.buildUrl("", filterGroupId)) .accept(MediaType.TEXT_PLAIN) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) diff --git a/rest-mvc/src/main/java/com/intuit/tank/rest/mvc/rest/clients/JobClient.java b/rest-mvc/src/main/java/com/intuit/tank/rest/mvc/rest/clients/JobClient.java index 40b0e0446..84212db9b 100644 --- a/rest-mvc/src/main/java/com/intuit/tank/rest/mvc/rest/clients/JobClient.java +++ b/rest-mvc/src/main/java/com/intuit/tank/rest/mvc/rest/clients/JobClient.java @@ -11,6 +11,8 @@ import com.intuit.tank.rest.mvc.rest.models.jobs.CreateJobRequest; import com.intuit.tank.rest.mvc.rest.models.jobs.JobContainer; import com.intuit.tank.rest.mvc.rest.models.jobs.JobTO; +import com.intuit.tank.vm.vmManager.models.CloudVmStatusContainer; +import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import reactor.core.publisher.Mono; @@ -39,7 +41,7 @@ public JobContainer getAllJobs() { .uri(baseUrl) .accept(MediaType.APPLICATION_JSON) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -52,7 +54,7 @@ public JobTO getJob(Integer jobId) { .uri(urlBuilder.buildUrl("", jobId)) .accept(MediaType.APPLICATION_JSON) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -65,7 +67,7 @@ public JobContainer getJobsByProject(Integer projectId) { .uri(urlBuilder.buildUrl("/project", projectId)) .accept(MediaType.APPLICATION_JSON) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -80,7 +82,7 @@ public Map createJob(CreateJobRequest request) { .accept(MediaType.APPLICATION_JSON) .body(Mono.just(request), CreateJobRequest.class) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -93,7 +95,7 @@ public List> getAllJobStatus() { .uri(urlBuilder.buildUrl("/status")) .accept(MediaType.APPLICATION_JSON) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -106,7 +108,7 @@ public String getJobStatus(Integer jobId) { .uri(urlBuilder.buildUrl("/status", jobId)) .accept(MediaType.TEXT_PLAIN) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -114,27 +116,27 @@ public String getJobStatus(Integer jobId) { .block(); } - public String getJobVMStatuses(String jobId) { + public CloudVmStatusContainer getJobVMStatuses(String jobId) { return client.get() .uri(urlBuilder.buildUrl("/instance-status", jobId)) .accept(MediaType.APPLICATION_JSON) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) - .bodyToMono(String.class) + .bodyToMono(CloudVmStatusContainer.class) .block(); } - // Job Status Setters + // Job Actions public String startJob(Integer jobId) { return client.get() .uri(urlBuilder.buildUrl("/start", jobId)) .accept(MediaType.TEXT_PLAIN) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -147,7 +149,7 @@ public String stopJob(Integer jobId) { .uri(urlBuilder.buildUrl("/stop", jobId)) .accept(MediaType.TEXT_PLAIN) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -160,7 +162,7 @@ public String pauseJob(Integer jobId) { .uri(urlBuilder.buildUrl("/pause", jobId)) .accept(MediaType.TEXT_PLAIN) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -173,7 +175,7 @@ public String resumeJob(Integer jobId) { .uri(urlBuilder.buildUrl("/resume", jobId)) .accept(MediaType.TEXT_PLAIN) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -186,7 +188,7 @@ public String killJob(Integer jobId) { .uri(urlBuilder.buildUrl("/kill", jobId)) .accept(MediaType.TEXT_PLAIN) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) diff --git a/rest-mvc/src/main/java/com/intuit/tank/rest/mvc/rest/clients/ProjectClient.java b/rest-mvc/src/main/java/com/intuit/tank/rest/mvc/rest/clients/ProjectClient.java index 981c6c0ef..32c00500a 100644 --- a/rest-mvc/src/main/java/com/intuit/tank/rest/mvc/rest/clients/ProjectClient.java +++ b/rest-mvc/src/main/java/com/intuit/tank/rest/mvc/rest/clients/ProjectClient.java @@ -45,7 +45,7 @@ public ProjectContainer getProjects() { .uri(baseUrl) .accept(MediaType.APPLICATION_JSON) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -58,7 +58,7 @@ public Map getProjectNames() { .get() .accept(MediaType.APPLICATION_JSON) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -71,7 +71,7 @@ public ProjectTO getProject(Integer projectId) { .uri(urlBuilder.buildUrl("", projectId)) .accept(MediaType.APPLICATION_JSON) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -86,7 +86,7 @@ public Map createProject(AutomationRequest request) { .accept(MediaType.APPLICATION_JSON) .body(Mono.just(request), AutomationRequest.class) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -101,7 +101,7 @@ public Map updateProject(AutomationRequest request) { .accept(MediaType.APPLICATION_JSON) .body(Mono.just(request), AutomationRequest.class) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -113,7 +113,7 @@ public String downloadTestScriptForProject(Integer projectId) { Flux dataBuffers = client.get() .uri(urlBuilder.buildUrl("/download", projectId)) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -136,7 +136,7 @@ public String deleteProject(Integer projectId) { .uri(urlBuilder.buildUrl("", projectId)) .accept(MediaType.TEXT_PLAIN) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) diff --git a/rest-mvc/src/main/java/com/intuit/tank/rest/mvc/rest/clients/ScriptClient.java b/rest-mvc/src/main/java/com/intuit/tank/rest/mvc/rest/clients/ScriptClient.java index f1109659e..5bf93ea8d 100644 --- a/rest-mvc/src/main/java/com/intuit/tank/rest/mvc/rest/clients/ScriptClient.java +++ b/rest-mvc/src/main/java/com/intuit/tank/rest/mvc/rest/clients/ScriptClient.java @@ -12,6 +12,7 @@ import com.intuit.tank.script.models.ExternalScriptTO; import com.intuit.tank.script.models.ScriptDescriptionContainer; import com.intuit.tank.script.models.ScriptTO; +import org.springframework.http.HttpStatus; import org.springframework.web.multipart.MultipartFile; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DataBufferUtils; @@ -45,7 +46,7 @@ public ScriptDescriptionContainer getScripts() { .uri(baseUrl) .accept(MediaType.APPLICATION_JSON) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -58,7 +59,7 @@ public ScriptTO getScript(Integer scriptId) { .uri(urlBuilder.buildUrl("", scriptId)) .accept(MediaType.APPLICATION_JSON) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -73,7 +74,7 @@ public ScriptTO createScript(ScriptTO scriptTo) { .accept(MediaType.APPLICATION_JSON) .body(Mono.just(scriptTo), ScriptTO.class) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -86,7 +87,7 @@ public Mono downloadScript(Integer scriptId) { .uri(urlBuilder.buildUrl("/download", scriptId)) .accept(MediaType.APPLICATION_OCTET_STREAM) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -97,7 +98,7 @@ public String downloadHarnessScript(Integer scriptId) { Flux dataBuffers = client.get() .uri(urlBuilder.buildUrl("/harness/download", scriptId)) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -125,7 +126,7 @@ public Map uploadScript(String name, Integer existingScriptId, M .queryParam("id", finalId) .build()) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -138,7 +139,7 @@ public String deleteScript(Integer scriptId) { .uri(urlBuilder.buildUrl("", scriptId)) .accept(MediaType.TEXT_PLAIN) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -153,7 +154,7 @@ public ExternalScriptContainer getExternalScripts() { .uri(urlBuilder.buildUrl("/external")) .accept(MediaType.APPLICATION_JSON) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -166,7 +167,7 @@ public ExternalScriptTO getExternalScript(Integer externalScriptId) { .uri(urlBuilder.buildUrl("/external", externalScriptId)) .accept(MediaType.APPLICATION_JSON) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -181,7 +182,7 @@ public ExternalScriptTO createExternalScript(ExternalScriptTO script) { .accept(MediaType.APPLICATION_JSON) .body(Mono.just(script), ExternalScriptTO.class) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -194,7 +195,7 @@ public Mono downloadExternalScript(Integer externalScriptId) { .uri(urlBuilder.buildUrl("/external/download", externalScriptId)) .accept(MediaType.APPLICATION_OCTET_STREAM) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) @@ -206,7 +207,7 @@ public String deleteExternalScript(Integer externalScriptId) { .uri(urlBuilder.buildUrl("/external", externalScriptId)) .accept(MediaType.TEXT_PLAIN) .retrieve() - .onStatus(status -> status.isError(), + .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) .flatMap(body -> Mono.error(new ClientException(body, response.statusCode().value())))) diff --git a/rest-mvc/src/main/java/com/intuit/tank/rest/mvc/rest/controllers/errors/GenericExceptionHandler.java b/rest-mvc/src/main/java/com/intuit/tank/rest/mvc/rest/controllers/errors/GenericExceptionHandler.java index 93f5482a0..ddb7d3b60 100644 --- a/rest-mvc/src/main/java/com/intuit/tank/rest/mvc/rest/controllers/errors/GenericExceptionHandler.java +++ b/rest-mvc/src/main/java/com/intuit/tank/rest/mvc/rest/controllers/errors/GenericExceptionHandler.java @@ -69,17 +69,17 @@ public SimpleErrorResponse handleInternalServerException(GenericServiceInternalS @ExceptionHandler(MultipartException.class) public ResponseEntity handleFileException(HttpServletRequest request, Throwable ex) { - return new ResponseEntity<>("File upload error: incorrect request or missing file parameter", HttpStatus.BAD_REQUEST); + return genericErrorResponse(HttpStatus.BAD_REQUEST, "File upload error: incorrect request or missing file parameter", ex); } @ExceptionHandler(MissingServletRequestPartException.class) public ResponseEntity handleMissingServletRequestPart(HttpServletRequest request, Throwable ex) { - return new ResponseEntity<>("File upload error: incorrect request or missing file parameter", HttpStatus.BAD_REQUEST); + return genericErrorResponse(HttpStatus.BAD_REQUEST, "File upload error: incorrect request or missing file parameter", ex); } @ExceptionHandler(HttpMessageNotReadableException.class) public ResponseEntity handleHttpMessageNotReadable(HttpServletRequest request, Throwable ex) { - return new ResponseEntity<>("Incorrect request body", HttpStatus.BAD_REQUEST); + return genericErrorResponse(HttpStatus.BAD_REQUEST, "Incorrect request body", ex); } @ExceptionHandler diff --git a/rest-mvc/src/main/resources/log4j2.xml b/rest-mvc/src/main/resources/log4j2.xml deleted file mode 100644 index a2c661873..000000000 --- a/rest-mvc/src/main/resources/log4j2.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/rest-mvc/src/test/java/com/intuit/tank/rest/mvc/rest/clients/AgentClientTest.java b/rest-mvc/src/test/java/com/intuit/tank/rest/mvc/rest/clients/AgentClientTest.java new file mode 100644 index 000000000..9537bf953 --- /dev/null +++ b/rest-mvc/src/test/java/com/intuit/tank/rest/mvc/rest/clients/AgentClientTest.java @@ -0,0 +1,400 @@ +package com.intuit.tank.rest.mvc.rest.clients; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.intuit.tank.rest.mvc.rest.clients.util.ClientException; +import com.intuit.tank.rest.mvc.rest.models.agent.TankHttpClientDefinitionContainer; +import com.intuit.tank.vm.agent.messages.*; +import com.intuit.tank.vm.api.enumerated.JobStatus; +import com.intuit.tank.vm.api.enumerated.VMImageType; +import com.intuit.tank.vm.api.enumerated.VMRegion; +import com.intuit.tank.vm.vmManager.models.CloudVmStatus; +import com.intuit.tank.vm.vmManager.models.VMStatus; +import com.intuit.tank.vm.vmManager.models.ValidationStatus; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import org.mockito.MockitoAnnotations; +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.core.io.buffer.DataBufferFactory; +import org.springframework.core.io.buffer.DefaultDataBufferFactory; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import java.io.IOException; +import java.util.Date; +import java.util.List; +import static org.junit.jupiter.api.Assertions.*; + +class AgentClientTest { + + MockWebServer mockWebServer; + + AgentClient agentClient; + + @BeforeEach + void setUp() throws IOException { + MockitoAnnotations.openMocks(this); + mockWebServer = new MockWebServer(); + mockWebServer.start(); + String serviceUrl = mockWebServer.url("/").toString(); + agentClient = new AgentClient(serviceUrl, null, null); + } + + @AfterEach + void tearDown() throws IOException { + mockWebServer.shutdown(); + } + + @Test + void testAgentClientDefaultConstructor_SetsFieldsCorrectly() { + String serviceUrl = "http://localhost:8080"; + AgentClient agentClient = new AgentClient(serviceUrl); + assertEquals("/v2/agent", agentClient.getServiceBaseUrl()); + } + + @Test + void testGetSettings_WhenSuccess_ReturnsSettings() throws InterruptedException { + String anySettings = "Any Settings"; + + mockWebServer.enqueue(new MockResponse().setBody(anySettings).addHeader("Content-Type", "application/xml")); + String response = agentClient.getSettings(); + assertEquals(anySettings, response); + assertEquals("GET /v2/agent/settings HTTP/1.1", mockWebServer.takeRequest().getRequestLine()); + } + + @Test + void testGetSettings_WhenError_ThrowsClientException() { + String errorBody = "Internal Server Error"; + int errorCode = 500; + + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(errorCode)); + Exception exception = assertThrows(ClientException.class, agentClient::getSettings); + assertTrue(exception.getMessage().contains(errorBody)); + } + + @Test + void testGetSupportFiles_WhenSuccess_ReturnsDataBuffer() { + DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory(); + DataBuffer expectedDataBuffer = dataBufferFactory.wrap("Any support files".getBytes()); + mockWebServer.enqueue(new MockResponse().setBody("Any support files").setHeader("Content-Type", "application/octet-stream")); + + + Mono responseMono = agentClient.getSupportFiles(); + + StepVerifier.create(responseMono) + .assertNext(dataBuffer -> { + assertEquals(expectedDataBuffer.readableByteCount(), dataBuffer.readableByteCount()); + assertEquals(expectedDataBuffer.asByteBuffer().compareTo(dataBuffer.asByteBuffer()), 0); + }) + .verifyComplete(); + } + + @Test + void testGetSupportFiles_WhenServerError_ThrowsClientException() { + String errorBody = "Internal Server Error"; + int errorCode = 500; + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(errorCode)); + + + Mono responseMono = agentClient.getSupportFiles(); + + StepVerifier.create(responseMono) + .expectErrorMatches(throwable -> throwable instanceof ClientException + && throwable.getMessage().contains(errorBody)) + .verify(); + } + + @Test + void testAgentReady_WhenSuccess_ReturnsAgentTestStartData() throws JsonProcessingException { + AgentData givenAgentData = new AgentData("234", "testInstanceId", "testInstanceUrl", + 1, VMRegion.US_EAST_2, "testZone"); + AgentTestStartData expectedTestStartData = new AgentTestStartData(); + mockWebServer.enqueue( + new MockResponse() + .setBody(new ObjectMapper().writeValueAsString(expectedTestStartData)) + .setHeader("Content-Type", "application/json") + ); + + + AgentTestStartData response = agentClient.agentReady(givenAgentData); + + assertEquals(expectedTestStartData.getJobId(), response.getJobId()); + assertEquals(expectedTestStartData.getRampTime(), response.getRampTime()); + assertEquals(expectedTestStartData.getSimulationTime(), response.getSimulationTime()); + assertEquals(expectedTestStartData.getStartUsers(), response.getStartUsers()); + assertEquals(expectedTestStartData.getConcurrentUsers(), response.getConcurrentUsers()); + assertEquals(expectedTestStartData.getIncrementStrategy(), response.getIncrementStrategy()); + assertEquals(expectedTestStartData.getUserIntervalIncrement(), response.getUserIntervalIncrement()); + assertEquals(expectedTestStartData.getDataFiles(), response.getDataFiles()); + assertEquals(expectedTestStartData.getAgentInstanceNum(), response.getAgentInstanceNum()); + } + + @Test + void testAgentReady_WhenServerError_ThrowsClientException() { + AgentData givenAgentData = new AgentData(); + String errorBody = "Internal Server Error"; + int errorCode = 500; + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(errorCode)); + + Exception exception = assertThrows( + ClientException.class, + () -> agentClient.agentReady(givenAgentData) + ); + assertTrue(exception.getMessage().contains(errorBody)); + } + + @Test + void testGetHeaders_WhenSuccess_ReturnsHeaders() throws JsonProcessingException { + String validHeadersXml = "" + + "
" + + "testKeytestValue" + + "
"; + mockWebServer.enqueue( + new MockResponse() + .setBody(validHeadersXml) // valid XML that corresponds to Headers object + .addHeader("Content-Type", "application/xml") + ); + Headers expectedHeaders = new Headers(List.of(new Header("testKey", "testValue"))); + + Headers response = agentClient.getHeaders(); + + assertEquals(expectedHeaders.getHeaders().get(0).getKey(), response.getHeaders().get(0).getKey()); + assertEquals(expectedHeaders.getHeaders().get(0).getValue(), response.getHeaders().get(0).getValue()); + } + + @Test + void testGetHeaders_WhenServerError_ThrowsClientException() { + String errorBody = "Internal Server Error"; + int errorCode = 500; + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(errorCode)); + + Exception exception = assertThrows( + ClientException.class, + agentClient::getHeaders + ); + assertTrue(exception.getMessage().contains(errorBody)); + } + + @Test + void testGetClients_WhenSuccess_ReturnsTankHttpClientDefinitionContainer() throws JsonProcessingException { + String validHeadersXml = "" + + "" + + "TestClient" + + "com.intuit.tank.test.client" + + "" + + "TestClient"; + + mockWebServer.enqueue( + new MockResponse() + .setBody(validHeadersXml) + .addHeader("Content-Type", "application/xml") + ); + + + TankHttpClientDefinitionContainer response = agentClient.getClients(); + + assertEquals("com.intuit.tank.test.client", response.getDefinitions().get(0).getClassName()); + assertEquals("TestClient", response.getDefinitions().get(0).getName()); + assertEquals("TestClient", response.getDefaultDefinition()); + } + + @Test + void testGetClients_WhenServerError_ThrowsClientException() { + String errorBody = "Internal Server Error"; + int errorCode = 500; + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(errorCode)); + + Exception exception = assertThrows( + ClientException.class, + agentClient::getClients + ); + assertTrue(exception.getMessage().contains(errorBody)); + } + + @Test + void testSetStandaloneAgentAvailability_WhenSuccess_ReturnsNull() { + AgentAvailability givenAgentAvailability = new AgentAvailability(); + mockWebServer.enqueue( + new MockResponse() + .setBody("") + .addHeader("Content-Type", "application/json") + ); + + + Void response = agentClient.setStandaloneAgentAvailability(givenAgentAvailability); + assertNull(response); + } + + @Test + void testSetStandaloneAgentAvailability_WhenServerError_ThrowsClientException() { + AgentAvailability givenAgentAvailability = new AgentAvailability(); + String errorBody = "Internal Server Error"; + int errorCode = 500; + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(errorCode)); + + Exception exception = assertThrows( + ClientException.class, + () -> agentClient.setStandaloneAgentAvailability(givenAgentAvailability) + ); + assertTrue(exception.getMessage().contains(errorBody)); + } + + @Test + void testGetInstanceStatus_WhenSuccess_ReturnsCloudVmStatus() throws JsonProcessingException { + CloudVmStatus cloudVmStatus = new CloudVmStatus( + "testInstanceId", + "234", + "testSecurityGroup", + JobStatus.Running, + VMImageType.AGENT, + VMRegion.US_WEST_2, + VMStatus.running, + new ValidationStatus(), + 100, + 50, + new Date(), + new Date() + ); + + mockWebServer.enqueue( + new MockResponse() + .setBody(new ObjectMapper().writeValueAsString(cloudVmStatus)) + .addHeader("Content-Type", "application/json") + ); + + + CloudVmStatus response = agentClient.getInstanceStatus("testInstanceId"); + + assertEquals(cloudVmStatus, response); + } + + @Test + void getInstanceStatus_WhenServerError_ThrowsClientException() { + String givenInstanceId = "instanceId"; + String errorBody = "Internal Server Error"; + int errorCode = 500; + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(errorCode)); + + Exception exception = assertThrows( + ClientException.class, + () -> agentClient.getInstanceStatus(givenInstanceId) + ); + assertTrue(exception.getMessage().contains(errorBody)); + } + + @Test + void testSetInstanceStatus_WhenSuccess_ReturnsNull() { + CloudVmStatus cloudVmStatus = new CloudVmStatus( + "testInstanceId", + "234", + "testSecurityGroup", + JobStatus.Running, + VMImageType.AGENT, + VMRegion.US_WEST_2, + VMStatus.running, + new ValidationStatus(), + 100, + 50, + new Date(), + new Date() + ); + + mockWebServer.enqueue( + new MockResponse() + .setBody("") + .addHeader("Content-Type", "application/json") + ); + + + Void response = agentClient.setInstanceStatus("testInstanceId", cloudVmStatus); + + assertNull(response); + } + + @Test + void setInstanceStatus_WhenServerError_ThrowsClientException() { + CloudVmStatus cloudVmStatus = new CloudVmStatus( + "testInstanceId", + "234", + "testSecurityGroup", + JobStatus.Running, + VMImageType.AGENT, + VMRegion.US_WEST_2, + VMStatus.running, + new ValidationStatus(), + 100, + 50, + new Date(), + new Date() + ); + String errorBody = "Internal Server Error"; + int errorCode = 500; + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(errorCode)); + + Exception exception = assertThrows( + ClientException.class, + () -> agentClient.setInstanceStatus("testInstanceId", cloudVmStatus) + ); + assertTrue(exception.getMessage().contains(errorBody)); + } + + // Instance Actions + + public enum InstanceActions { + STOP, + PAUSE, + RESUME, + KILL + } + + @ParameterizedTest + @EnumSource(InstanceActions.class) + void testInstanceActions_WhenSuccess_ReturnsString(InstanceActions operation) { + String instanceId = "testInstanceId"; + String expectedResponse = "InstanceStatus"; + + mockWebServer.enqueue( + new MockResponse() + .setBody(expectedResponse) + .addHeader("Content-Type", "text/plain")); + + String response = performOperation(operation, instanceId); + + assertEquals(expectedResponse, response); + } + + @ParameterizedTest + @EnumSource(InstanceActions.class) + void testInstanceActions_WhenServerError_ThrowsClientException(InstanceActions operation) { + String instanceId = "testInstanceId"; + String errorBody = "Internal Server Error"; + + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(500)); + + Exception exception = assertThrows( + ClientException.class, + () -> performOperation(operation, instanceId) + ); + assertTrue(exception.getMessage().contains(errorBody)); + } + + private String performOperation(InstanceActions operation, String instanceId) { + switch (operation) { + case STOP: + return agentClient.stopInstance(instanceId); + case PAUSE: + return agentClient.pauseInstance(instanceId); + case RESUME: + return agentClient.resumeInstance(instanceId); + case KILL: + return agentClient.killInstance(instanceId); + default: + throw new IllegalArgumentException("Invalid Instance Action: " + operation); + } + } +} diff --git a/rest-mvc/src/test/java/com/intuit/tank/rest/mvc/rest/clients/BaseClientTest.java b/rest-mvc/src/test/java/com/intuit/tank/rest/mvc/rest/clients/BaseClientTest.java new file mode 100644 index 000000000..60b02be5f --- /dev/null +++ b/rest-mvc/src/test/java/com/intuit/tank/rest/mvc/rest/clients/BaseClientTest.java @@ -0,0 +1,98 @@ +package com.intuit.tank.rest.mvc.rest.clients; + +import com.intuit.tank.rest.mvc.rest.clients.util.ClientException; + +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.MockitoAnnotations; +import static org.junit.jupiter.api.Assertions.*; + +import java.io.IOException; + +class BaseClientTest { + + MockWebServer mockWebServer; + + @BeforeEach + void setUp() throws IOException { + MockitoAnnotations.openMocks(this); + mockWebServer = new MockWebServer(); + mockWebServer.start(); + } + + @AfterEach + void tearDown() throws IOException { + mockWebServer.shutdown(); + } + + @Test + void testConstructor_WithProxy_SetsCorrectBaseUrlAndCreatesClient() { + + BaseClient baseClient = new BaseClient("http://localhost:8080", "proxy.test.com", 8080) { + @Override + protected String getServiceBaseUrl() { + return "/v2/data"; + } + }; + assertEquals("http://localhost:8080/v2/data", baseClient.baseUrl); + assertNotNull(baseClient.client); + } + + @Test + void testConstructor_WithoutProxy_SetsCorrectBaseUrlAndCreatesClient() { + BaseClient baseClient = new BaseClient("http://localhost:8080", null, null) { + @Override + protected String getServiceBaseUrl() { + return "/v2/ping"; + } + }; + assertEquals("http://localhost:8080/v2/ping", baseClient.baseUrl); + assertNotNull(baseClient.client); + } + + @Test + void testSettingBaseUrl_ChangesBaseUrl() { + BaseClient baseClient = new BaseClient("http://localhost:8080", null, null) { + @Override + protected String getServiceBaseUrl() { + return "/v2/ping"; + } + }; + baseClient.setBaseUrl("https://test-instance.com"); + assertEquals("https://test-instance.com/v2/ping", baseClient.baseUrl); + } + + + @Test + void testPing_Success_ReturnsOk() throws InterruptedException { + String serviceUrl = mockWebServer.url("/").toString(); + BaseClient baseClient = new BaseClient(serviceUrl, null, null) { + @Override + protected String getServiceBaseUrl() { + return "/"; + } + }; + mockWebServer.enqueue(new MockResponse().setBody("OK")); + baseClient.ping(); + assertEquals("GET /ping HTTP/1.1", mockWebServer.takeRequest().getRequestLine()); + } + + + @Test + void testPing_Failure_ThrowsClientException() { + String serviceUrl = mockWebServer.url("/").toString(); + BaseClient baseClient = new BaseClient(serviceUrl, null, null) { + @Override + protected String getServiceBaseUrl() { + return "/"; + } + }; + mockWebServer.enqueue(new MockResponse().setResponseCode(500).setBody("Interval Service Error")); + Exception exception = assertThrows(ClientException.class, baseClient::ping); + assertTrue(exception.getMessage().contains("Interval Service Error")); + } +} + diff --git a/rest-mvc/src/test/java/com/intuit/tank/rest/mvc/rest/clients/DataFileClientTest.java b/rest-mvc/src/test/java/com/intuit/tank/rest/mvc/rest/clients/DataFileClientTest.java new file mode 100644 index 000000000..b05a5a9d5 --- /dev/null +++ b/rest-mvc/src/test/java/com/intuit/tank/rest/mvc/rest/clients/DataFileClientTest.java @@ -0,0 +1,242 @@ +package com.intuit.tank.rest.mvc.rest.clients; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.intuit.tank.rest.mvc.rest.clients.util.ClientException; +import com.intuit.tank.rest.mvc.rest.models.datafiles.DataFileDescriptor; +import com.intuit.tank.rest.mvc.rest.models.datafiles.DataFileDescriptorContainer; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.MockitoAnnotations; +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.core.io.buffer.DataBufferFactory; +import org.springframework.core.io.buffer.DefaultDataBufferFactory; +import org.springframework.http.ResponseEntity; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.web.multipart.MultipartFile; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.*; + +public class DataFileClientTest { + MockWebServer mockWebServer; + + DataFileClient dataFileClient; + + @BeforeEach + void setUp() throws IOException { + MockitoAnnotations.openMocks(this); + mockWebServer = new MockWebServer(); + mockWebServer.start(); + String serviceUrl = mockWebServer.url("/").toString(); + dataFileClient = new DataFileClient(serviceUrl, null, null); + } + + @AfterEach + void tearDown() throws IOException { + mockWebServer.shutdown(); + } + + @Test + void testDataFileClientDefaultConstructor_SetsFieldsCorrectly() { + String serviceUrl = "http://localhost:8080"; + DataFileClient agentClient = new DataFileClient(serviceUrl); + assertEquals("/v2/datafiles", agentClient.getServiceBaseUrl()); + } + + @Test + void testGetDatafiles_WhenSuccess_ReturnsDataFileDescriptorContainer() throws JsonProcessingException { + DataFileDescriptor dataFileDescriptor = new DataFileDescriptor(); + dataFileDescriptor.setName("testName"); + List list = List.of(dataFileDescriptor); + DataFileDescriptorContainer expectedContainer = new DataFileDescriptorContainer(list); + mockWebServer.enqueue( + new MockResponse() + .setBody(new ObjectMapper().writeValueAsString(expectedContainer)) + .addHeader("Content-Type", "application/json") + ); + + DataFileDescriptorContainer response = dataFileClient.getDatafiles(); + assertEquals(expectedContainer.getDataFiles().get(0).getName(), response.getDataFiles().get(0).getName()); + } + + @Test + void testGetDatafiles_WhenServerError_ThrowsClientException() { + String errorBody = "Internal Server Error"; + int errorCode = 500; + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(errorCode)); + + Exception exception = assertThrows( + ClientException.class, + () -> dataFileClient.getDatafiles() + ); + assertTrue(exception.getMessage().contains(errorBody)); + + } + + @Test + void testGetDatafile_WhenSuccess_ReturnsDataFileDescriptor() throws JsonProcessingException { + Integer datafileId = 17; + DataFileDescriptor expectedDescriptor = new DataFileDescriptor(); + expectedDescriptor.setId(datafileId); + mockWebServer.enqueue( + new MockResponse() + .setBody(new ObjectMapper().writeValueAsString(expectedDescriptor)) + .addHeader("Content-Type", "application/json") + ); + + DataFileDescriptor response = dataFileClient.getDatafile(datafileId); + assertEquals(expectedDescriptor.getId(), response.getId()); + } + + @Test + void testGetDatafile_WhenServerError_ThrowsClientException() { + Integer datafileId = 18; + String errorBody = "Internal Server Error"; + int errorCode = 500; + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(errorCode)); + + Exception exception = assertThrows( + ClientException.class, + () -> dataFileClient.getDatafile(datafileId) + ); + assertTrue(exception.getMessage().contains(errorBody)); + } + + @Test + void testGetDatafileContent_WhenSuccess_ReturnsContentString() { + Integer datafileId = 19; + String expectedContent = "Test File Content"; + mockWebServer.enqueue( + new MockResponse() + .setBody(expectedContent) + .addHeader("Content-Type", "text/plain") + ); + + String response = dataFileClient.getDatafileContent(datafileId); + assertEquals(expectedContent, response); + } + + @Test + void testGetDatafileContent_WhenServerError_ThrowsClientException() { + Integer datafileId = 20; + String errorBody = "Internal Server Error"; + int errorCode = 500; + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(errorCode)); + + Exception exception = assertThrows( + ClientException.class, + () -> dataFileClient.getDatafileContent(datafileId) + ); + assertTrue(exception.getMessage().contains(errorBody)); + } + + @Test + void testDownloadDatafile_WhenSuccess_ReturnsDataBuffer() { + Integer datafileId = 32; + DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory(); + DataBuffer expectedDataBuffer = dataBufferFactory.wrap("Test Datafile Content".getBytes()); + mockWebServer.enqueue(new MockResponse().setBody("Test Datafile Content").setHeader("Content-Type", "application/octet-stream")); + Mono responseMono = dataFileClient.downloadDatafile(datafileId); + + StepVerifier.create(responseMono) + .assertNext(dataBuffer -> { + assertEquals(expectedDataBuffer.readableByteCount(), dataBuffer.readableByteCount()); + assertEquals(expectedDataBuffer.asByteBuffer().compareTo(dataBuffer.asByteBuffer()), 0); + }) + .verifyComplete(); + } + + @Test + void testDownloadDatafile_WhenServerError_ThrowsClientException() { + Integer datafileId = 32; + String errorBody = "Internal Server Error"; + int errorCode = 500; + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(errorCode)); + Mono responseMono = dataFileClient.downloadDatafile(datafileId); + + StepVerifier.create(responseMono) + .expectErrorMatches(throwable -> throwable instanceof ClientException + && throwable.getMessage().contains(errorBody)) + .verify(); + } + + @Test + void testUploadDatafile_WhenSuccess_ReturnsMap() throws JsonProcessingException { + Integer id = 45; + MultipartFile file = new MockMultipartFile("file", "file.txt", "text/plain", "test data".getBytes()); + + Map expectedResponse = new HashMap<>(); + expectedResponse.put("message", "Datafile with new datafile ID" + id + "has been uploaded"); + mockWebServer.enqueue( + new MockResponse() + .setBody(new ObjectMapper().writeValueAsString(expectedResponse)) + .addHeader("Content-Type", "application/json") + ); + Mono>> response = dataFileClient.uploadDatafile(id, file); + + StepVerifier.create(response.map(ResponseEntity::getBody)) + .consumeNextWith(actual -> assertEquals(expectedResponse, actual)) + .expectComplete() + .verify(); + } + + @Test + void uploadDatafile_WhenServerError_ThrowsClientException() { + Integer id = 46; + MultipartFile file = new MockMultipartFile("file", "file.txt", "text/plain", "test data".getBytes()); + + String errorBody = "Internal Server Error"; + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(500)); + + Mono>> response = dataFileClient.uploadDatafile(id, file); + + StepVerifier.create(response) + .expectErrorMatches(throwable -> throwable instanceof ClientException + && throwable.getMessage().equals(errorBody)) + .verify(); + } + + @Test + void testDeleteDatafile_WhenSuccess_ReturnsString() { + Integer datafileId = 50; + String expectedResponse = "Datafile deleted successfully"; + mockWebServer.enqueue( + new MockResponse() + .setBody(expectedResponse) + .addHeader("Content-Type", "text/plain") + ); + + String serviceUrl = mockWebServer.url("/").toString(); + DataFileClient dataFileClient = new DataFileClient(serviceUrl, null, null); + String response = dataFileClient.deleteDatafile(datafileId); + + assertEquals(expectedResponse, response); + } + + @Test + void testDeleteDatafile_WhenServerError_ThrowsClientException() { + Integer datafileId = 51; + String errorBody = "Internal Server Error"; + int errorCode = 500; + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(errorCode)); + + String serviceUrl = mockWebServer.url("/").toString(); + DataFileClient dataFileClient = new DataFileClient(serviceUrl, null, null); + + Exception exception = assertThrows( + ClientException.class, + () -> dataFileClient.deleteDatafile(datafileId) + ); + assertTrue(exception.getMessage().contains(errorBody)); + } +} diff --git a/rest-mvc/src/test/java/com/intuit/tank/rest/mvc/rest/clients/FilterClientTest.java b/rest-mvc/src/test/java/com/intuit/tank/rest/mvc/rest/clients/FilterClientTest.java new file mode 100644 index 000000000..62dcf2a65 --- /dev/null +++ b/rest-mvc/src/test/java/com/intuit/tank/rest/mvc/rest/clients/FilterClientTest.java @@ -0,0 +1,258 @@ +package com.intuit.tank.rest.mvc.rest.clients; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.intuit.tank.rest.mvc.rest.clients.util.ClientException; +import com.intuit.tank.rest.mvc.rest.models.filters.*; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.MockitoAnnotations; + +import java.io.IOException; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +public class FilterClientTest { + + MockWebServer mockWebServer; + + FilterClient filterClient; + + @BeforeEach + void setUp() throws IOException { + MockitoAnnotations.openMocks(this); + mockWebServer = new MockWebServer(); + mockWebServer.start(); + String serviceUrl = mockWebServer.url("/").toString(); + filterClient = new FilterClient(serviceUrl, null, null); + } + + @AfterEach + void tearDown() throws IOException { + mockWebServer.shutdown(); + } + + @Test + void testFilterClientDefaultConstructor_SetsFieldsCorrectly() { + String serviceUrl = "http://localhost:8080"; + FilterClient filterClient = new FilterClient(serviceUrl); + assertEquals("/v2/filters", filterClient.getServiceBaseUrl()); + } + + @Test + void testGetFilters_WhenSuccess_ReturnsFilterContainer() throws JsonProcessingException { + FilterTO filter = new FilterTO(); + filter.setId(23); + List filters = List.of(filter); + FilterContainer expectedContainer = new FilterContainer(filters); + mockWebServer.enqueue( + new MockResponse() + .setBody(new ObjectMapper().writeValueAsString(expectedContainer)) + .addHeader("Content-Type", "application/json") + ); + + FilterContainer response = filterClient.getFilters(); + + assertEquals(expectedContainer.getFilters().get(0).getId(), response.getFilters().get(0).getId()); + } + + @Test + void testGetFilters_WhenServerError_ThrowsClientException() { + String errorBody = "Internal Server Error"; + int errorCode = 500; + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(errorCode)); + + Exception exception = assertThrows( + ClientException.class, + filterClient::getFilters + ); + assertTrue(exception.getMessage().contains(errorBody)); + } + + @Test + void testGetFilterGroups_WhenSuccess_ReturnsFilterGroupContainer() throws JsonProcessingException { + FilterGroupTO filterGroup = new FilterGroupTO(); + filterGroup.setId(23); + List filterGroups = List.of(filterGroup); + FilterGroupContainer expectedContainer = new FilterGroupContainer(filterGroups); + mockWebServer.enqueue( + new MockResponse() + .setBody(new ObjectMapper().writeValueAsString(expectedContainer)) + .addHeader("Content-Type", "application/json") + ); + + FilterGroupContainer response = filterClient.getFilterGroups(); + + assertEquals(expectedContainer.getFilterGroups().get(0).getId(), response.getFilterGroups().get(0).getId()); + } + + @Test + void testGetFilterGroups_WhenServerError_ThrowsClientException() { + String errorBody = "Internal Server Error"; + int errorCode = 500; + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(errorCode)); + + Exception exception = assertThrows( + ClientException.class, + filterClient::getFilterGroups + ); + assertTrue(exception.getMessage().contains(errorBody)); + } + + @Test + void testGetFilter_WhenSuccess_ReturnsFilterTO() throws JsonProcessingException { + Integer filterId = 60; + FilterTO filter = new FilterTO(); + filter.setId(filterId); + mockWebServer.enqueue( + new MockResponse() + .setBody(new ObjectMapper().writeValueAsString(filter)) + .addHeader("Content-Type", "application/json") + ); + + FilterTO response = filterClient.getFilter(filterId); + + assertEquals(filter.getId(), response.getId()); + } + + @Test + void testGetFilter_WhenServerError_ThrowsClientException() { + Integer filterId = 61; + String errorBody = "Internal Server Error"; + int errorCode = 500; + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(errorCode)); + + Exception exception = assertThrows( + ClientException.class, + () -> filterClient.getFilter(filterId) + ); + assertTrue(exception.getMessage().contains(errorBody)); + } + + @Test + void testGetFilterGroup_WhenSuccess_ReturnsFilterGroupTO() throws JsonProcessingException { + Integer filterGroupId = 61; + FilterGroupTO filterGroup = new FilterGroupTO(); + filterGroup.setId(filterGroupId); + mockWebServer.enqueue( + new MockResponse() + .setBody(new ObjectMapper().writeValueAsString(filterGroup)) + .addHeader("Content-Type", "application/json") + ); + + FilterGroupTO response = filterClient.getFilterGroup(filterGroupId); + + assertEquals(filterGroup.getId(), response.getId()); + } + + @Test + void testGetFilterGroup_WhenServerError_ThrowsClientException() { + Integer filterGroupId = 65; + String errorBody = "Internal Server Error"; + int errorCode = 500; + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(errorCode)); + + Exception exception = assertThrows( + ClientException.class, + () -> filterClient.getFilterGroup(filterGroupId) + ); + assertTrue(exception.getMessage().contains(errorBody)); + } + + @Test + void testApplyFilters_WhenSuccess_ReturnsString() { + Integer scriptId = 67; + ApplyFiltersRequest request = new ApplyFiltersRequest(); + String expectedResponse = "Filters applied successfully"; + + mockWebServer.enqueue( + new MockResponse() + .setBody(expectedResponse) + .addHeader("Content-Type", "text/plain") + ); + + String response = filterClient.applyFilters(scriptId, request); + + assertEquals(expectedResponse, response); + } + + @Test + void testApplyFilters_WhenServerError_ThrowsClientException() { + Integer scriptId = 72; + ApplyFiltersRequest request = new ApplyFiltersRequest(); + String errorBody = "Internal Server Error"; + + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(500)); + + Exception exception = assertThrows( + ClientException.class, + () -> filterClient.applyFilters(scriptId, request) + ); + assertTrue(exception.getMessage().contains(errorBody)); + } + + @Test + void testDeleteFilter_WhenSuccess_ReturnsString() { + Integer filterId = 15; + String expectedResponse = "Filter deleted successfully"; + + mockWebServer.enqueue( + new MockResponse() + .setBody(expectedResponse) + .addHeader("Content-Type", "text/plain") + ); + String response = filterClient.deleteFilter(filterId); + + assertEquals(expectedResponse, response); + } + + + @Test + void testDeleteFilter_WhenServerError_ThrowsClientException() { + Integer filterId = 17; + String errorBody = "Internal Server Error"; + + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(500)); + + Exception exception = assertThrows( + ClientException.class, + () -> filterClient.deleteFilter(filterId) + ); + assertTrue(exception.getMessage().contains(errorBody)); + } + + + @Test + void testDeleteFilterGroup_WhenSuccess_ReturnsString() { + Integer filterGroupId = 11; + String expectedResponse = "Filter group deleted successfully"; + + mockWebServer.enqueue( + new MockResponse() + .setBody(expectedResponse) + .addHeader("Content-Type", "text/plain") + ); + String response = filterClient.deleteFilterGroup(filterGroupId); + + assertEquals(expectedResponse, response); + } + + + @Test + void testDeleteFilterGroup_WhenServerError_ThrowsClientException() { + Integer filterGroupId = 12; + String errorBody = "Internal Server Error"; + + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(500)); + + Exception exception = assertThrows( + ClientException.class, + () -> filterClient.deleteFilterGroup(filterGroupId) + ); + assertTrue(exception.getMessage().contains(errorBody)); + } +} diff --git a/rest-mvc/src/test/java/com/intuit/tank/rest/mvc/rest/clients/JobClientTest.java b/rest-mvc/src/test/java/com/intuit/tank/rest/mvc/rest/clients/JobClientTest.java new file mode 100644 index 000000000..587503a7b --- /dev/null +++ b/rest-mvc/src/test/java/com/intuit/tank/rest/mvc/rest/clients/JobClientTest.java @@ -0,0 +1,350 @@ +package com.intuit.tank.rest.mvc.rest.clients; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.intuit.tank.rest.mvc.rest.clients.util.ClientException; +import com.intuit.tank.rest.mvc.rest.models.jobs.*; +import com.intuit.tank.vm.api.enumerated.JobStatus; +import com.intuit.tank.vm.api.enumerated.VMImageType; +import com.intuit.tank.vm.api.enumerated.VMRegion; +import com.intuit.tank.vm.vmManager.models.CloudVmStatus; +import com.intuit.tank.vm.vmManager.models.CloudVmStatusContainer; +import com.intuit.tank.vm.vmManager.models.VMStatus; +import com.intuit.tank.vm.vmManager.models.ValidationStatus; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import org.mockito.MockitoAnnotations; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.*; + +import static org.junit.jupiter.api.Assertions.*; + +public class JobClientTest { + MockWebServer mockWebServer; + + JobClient jobClient; + + @BeforeEach + void setUp() throws IOException { + MockitoAnnotations.openMocks(this); + mockWebServer = new MockWebServer(); + mockWebServer.start(); + String serviceUrl = mockWebServer.url("/").toString(); + jobClient = new JobClient(serviceUrl, null, null); + } + + @AfterEach + void tearDown() throws IOException { + mockWebServer.shutdown(); + } + + @Test + void testJobClientDefaultConstructor_SetsFieldsCorrectly() { + String serviceUrl = "http://localhost:8080"; + JobClient jobClient = new JobClient(serviceUrl); + assertEquals("/v2/jobs", jobClient.getServiceBaseUrl()); + } + + @Test + void testGetAllJobs_WhenSuccess_ReturnsJobContainer() throws JsonProcessingException { + JobTO jobTO = new JobTO(); + jobTO.setId(33); + JobContainer expectedContainer = new JobContainer(List.of(jobTO)); + mockWebServer.enqueue( + new MockResponse() + .setBody(new ObjectMapper().writeValueAsString(expectedContainer)) + .addHeader("Content-Type", "application/json") + ); + + JobContainer response = jobClient.getAllJobs(); + + assertEquals(expectedContainer.getJobs().get(0).getId(), response.getJobs().get(0).getId()); + } + + @Test + void testGetAllJobs_WhenServerError_ThrowsClientException() { + String errorBody = "Internal Server Error"; + int errorCode = 500; + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(errorCode)); + + String serviceUrl = mockWebServer.url("/").toString(); + JobClient jobClient = new JobClient(serviceUrl); + + Exception exception = assertThrows( + ClientException.class, + jobClient::getAllJobs + ); + assertTrue(exception.getMessage().contains(errorBody)); + } + + @Test + void testGetJob_WhenSuccess_ReturnsJobTO() throws JsonProcessingException { + Integer jobId = 1; + JobTO expectedResponse = new JobTO(); + expectedResponse.setId(44); + expectedResponse.setName("testJob"); + expectedResponse.setRampTimeMilis(1000L); + expectedResponse.setSimulationTimeMilis(60000L); + + mockWebServer.enqueue( + new MockResponse() + .setBody(new ObjectMapper().writeValueAsString(expectedResponse)) + .addHeader("Content-Type", "application/json") + ); + + JobTO response = jobClient.getJob(jobId); + + assertEquals(expectedResponse.getId(), response.getId()); + assertEquals(expectedResponse.getName(), response.getName()); + assertEquals(expectedResponse.getRampTimeMilis(), response.getRampTimeMilis()); + assertEquals(expectedResponse.getSimulationTimeMilis(), response.getSimulationTimeMilis()); + } + + @Test + void testGetJob_WhenServerError_ThrowsClientException() { + Integer jobId = 43; + String errorBody = "Internal Server Error"; + + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(500)); + + Exception exception = assertThrows(ClientException.class, + () -> jobClient.getJob(jobId) + ); + assertTrue(exception.getMessage().contains(errorBody)); + } + + + + @Test + void testGetJobsByProject_WhenSuccess_ReturnsJobContainer() throws JsonProcessingException { + Integer projectId = 33; + JobTO jobTO = new JobTO(); + jobTO.setId(projectId); + List jobs = List.of(jobTO); + JobContainer expectedContainer = new JobContainer(jobs); + mockWebServer.enqueue( + new MockResponse() + .setBody(new ObjectMapper().writeValueAsString(expectedContainer)) + .addHeader("Content-Type", "application/json") + ); + JobContainer response = jobClient.getJobsByProject(projectId); + + assertEquals(expectedContainer.getJobs().get(0).getId(), response.getJobs().get(0).getId()); + } + + @Test + void testGetJobsByProject_WhenServerError_ThrowsClientException() { + Integer projectId = 34; + String errorBody = "Internal Server Error"; + + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(500)); + + Exception exception = assertThrows(ClientException.class, () -> jobClient.getJobsByProject(projectId)); + assertTrue(exception.getMessage().contains(errorBody)); + } + + + @Test + void testCreateJob_WhenSuccess_ReturnsMap() throws JsonProcessingException { + CreateJobRequest request = new CreateJobRequest(); + Map expectedResponse = new HashMap<>(); + expectedResponse.put("jobId", "14"); + expectedResponse.put("status", "created"); + + mockWebServer.enqueue( + new MockResponse() + .setBody(new ObjectMapper().writeValueAsString(expectedResponse)) + .addHeader("Content-Type", "application/json") + ); + Map response = jobClient.createJob(request); + + assertEquals(expectedResponse, response); + } + + @Test + void testCreateJob_WhenServerError_ThrowsClientException() { + CreateJobRequest request = new CreateJobRequest(); + String errorBody = "Internal Server Error"; + + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(500)); + + Exception exception = assertThrows( + ClientException.class, + () -> jobClient.createJob(request) + ); + assertTrue(exception.getMessage().contains(errorBody)); + } + + @Test + void testGetAllJobStatus_WhenSuccess_ReturnsList() throws JsonProcessingException { + List> expectedList = new ArrayList<>(); + Map expectedMap = new HashMap<>(); + expectedMap.put("jobId", "1"); + expectedMap.put("status", "created"); + expectedList.add(expectedMap); + + mockWebServer.enqueue( + new MockResponse() + .setBody(new ObjectMapper().writeValueAsString(expectedList)) + .addHeader("Content-Type", "application/json") + ); + List> response = jobClient.getAllJobStatus(); + + assertEquals(expectedList, response); + } + + @Test + void testGetAllJobStatus_WhenServerError_ThrowsClientException() { + String errorBody = "Internal Server Error"; + mockWebServer.enqueue( + new MockResponse().setBody(errorBody).setResponseCode(500)); + + Exception exception = assertThrows( + ClientException.class, + jobClient::getAllJobStatus + ); + assertTrue(exception.getMessage().contains(errorBody)); + } + + @Test + void testGetJobStatus_WhenSuccess_ReturnsJobStatus() { + Integer jobId = 2; + String expectedResponse = "Running"; + + mockWebServer.enqueue( + new MockResponse() + .setBody(expectedResponse) + .addHeader("Content-Type", "text/plain") + ); + String response = jobClient.getJobStatus(jobId); + + assertEquals(expectedResponse, response); + } + + @Test + void testGetJobStatus_WhenServerError_ThrowsClientException() { + Integer jobId = 3; + String errorBody = "Internal Server Error"; + + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(500)); + + Exception exception = assertThrows( + ClientException.class, + () -> jobClient.getJobStatus(jobId) + ); + assertTrue(exception.getMessage().contains(errorBody)); + } + + @Test + void testGetJobVMStatuses_WhenSuccess_ReturnsJobStatuses() throws JsonProcessingException{ + String jobId = "234"; + CloudVmStatus expectedCloudVmStatus = new CloudVmStatus( + "testInstanceId", + "234", + "testSecurityGroup", + JobStatus.Running, + VMImageType.AGENT, + VMRegion.US_WEST_2, + VMStatus.running, + new ValidationStatus(), + 100, + 50, + new Date(), + new Date() + ); + + CloudVmStatusContainer cloudVmStatusContainer = new CloudVmStatusContainer(Set.of(expectedCloudVmStatus)); + + mockWebServer.enqueue( + new MockResponse() + .setBody(new ObjectMapper().writeValueAsString(cloudVmStatusContainer)) + .addHeader("Content-Type", "application/json") + ); + + CloudVmStatusContainer response = jobClient.getJobVMStatuses(jobId); + + CloudVmStatus actualCloudVmStatus = response.getStatuses().iterator().next(); + + assertEquals(jobId, actualCloudVmStatus.getJobId()); + assertEquals(expectedCloudVmStatus, actualCloudVmStatus); + } + + @Test + void testGetJobVMStatuses_WhenServerError_ThrowsClientException() { + String jobId = "243"; + String errorBody = "Internal Server Error"; + + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(500)); + + Exception exception = assertThrows( + ClientException.class, + () -> jobClient.getJobVMStatuses(jobId) + ); + assertTrue(exception.getMessage().contains(errorBody)); + } + + // Job Actions + + public enum JobActions { + START, + STOP, + PAUSE, + RESUME, + KILL + } + + @ParameterizedTest + @EnumSource(JobActions.class) + void jobOperation_WhenSuccess_ReturnsString(JobActions operation) { + Integer jobId = 23; + String expectedResponse = "JobStatus"; + + mockWebServer.enqueue( + new MockResponse() + .setBody(expectedResponse) + .addHeader("Content-Type", "text/plain")); + + String response = performOperation(operation, jobId); + + assertEquals(expectedResponse, response); + } + + @ParameterizedTest + @EnumSource(JobActions.class) + void jobOperation_WhenServerError_ThrowsClientException(JobActions operation) { + Integer jobId = 24; + String errorBody = "Internal Server Error"; + + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(500)); + + Exception exception = assertThrows( + ClientException.class, + () -> performOperation(operation, jobId) + ); + assertTrue(exception.getMessage().contains(errorBody)); + } + + private String performOperation(JobActions operation, Integer jobId) { + switch (operation) { + case START: + return jobClient.startJob(jobId); + case STOP: + return jobClient.stopJob(jobId); + case PAUSE: + return jobClient.pauseJob(jobId); + case RESUME: + return jobClient.resumeJob(jobId); + case KILL: + return jobClient.killJob(jobId); + default: + throw new IllegalArgumentException("Invalid Job Action: " + operation); + } + } +} diff --git a/rest-mvc/src/test/java/com/intuit/tank/rest/mvc/rest/clients/ProjectClientTest.java b/rest-mvc/src/test/java/com/intuit/tank/rest/mvc/rest/clients/ProjectClientTest.java new file mode 100644 index 000000000..602847800 --- /dev/null +++ b/rest-mvc/src/test/java/com/intuit/tank/rest/mvc/rest/clients/ProjectClientTest.java @@ -0,0 +1,279 @@ +package com.intuit.tank.rest.mvc.rest.clients; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.intuit.tank.rest.mvc.rest.clients.util.ClientException; +import com.intuit.tank.rest.mvc.rest.models.projects.*; +import com.intuit.tank.vm.api.enumerated.IncrementStrategy; +import com.intuit.tank.vm.api.enumerated.TerminationPolicy; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.MockitoAnnotations; + +import java.io.IOException; +import java.util.*; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.*; + +public class ProjectClientTest { + MockWebServer mockWebServer; + + ProjectClient projectClient; + + @BeforeEach + void setUp() throws IOException { + MockitoAnnotations.openMocks(this); + mockWebServer = new MockWebServer(); + mockWebServer.start(); + String serviceUrl = mockWebServer.url("/").toString(); + projectClient = new ProjectClient(serviceUrl, null, null); + } + + @AfterEach + void tearDown() throws IOException { + mockWebServer.shutdown(); + } + + @Test + void testProjectClientDefaultConstructor_SetsFieldsCorrectly() { + String serviceUrl = "http://localhost:8080"; + ProjectClient projectClient = new ProjectClient(serviceUrl); + + assertEquals("/v2/projects", projectClient.getServiceBaseUrl()); + } + + @Test + void testGetProjects_WhenSuccess_ReturnsProjectContainer() throws JsonProcessingException { + ProjectTO projectTO = new ProjectTO(); + projectTO.setId(4); + projectTO.setName("testName"); + projectTO.setRampTime("1h"); + projectTO.setSimulationTime(60000L); + projectTO.setTerminationPolicy(TerminationPolicy.script); + projectTO.setWorkloadType(IncrementStrategy.increasing); + ProjectContainer expectedResponse = new ProjectContainer(List.of(projectTO)); + mockWebServer.enqueue( + new MockResponse() + .setBody(new ObjectMapper().writeValueAsString(expectedResponse)) + .addHeader("Content-Type", "application/json") + ); + ProjectContainer response = projectClient.getProjects(); + ProjectTO expectedProjectTO = expectedResponse.getProjects().get(0); + + assertEquals(expectedProjectTO.getId(), projectTO.getId()); + assertEquals(expectedProjectTO.getName(), projectTO.getName()); + assertEquals(expectedProjectTO.getRampTime(), projectTO.getRampTime()); + assertEquals(expectedProjectTO.getSimulationTime(), projectTO.getSimulationTime()); + assertEquals(expectedProjectTO.getTerminationPolicy(), projectTO.getTerminationPolicy()); + assertEquals(expectedProjectTO.getWorkloadType(), projectTO.getWorkloadType()); + } + + @Test + void testGetProjects_WhenServerError_ThrowsClientException() { + String errorBody = "Internal Server Error"; + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(500)); + Exception exception = assertThrows( + ClientException.class, + () -> projectClient.getProjects() + ); + assertTrue(exception.getMessage().contains(errorBody)); + } + + @Test + void testGetProjectNames_WhenSuccess_ReturnsProjectNames() throws JsonProcessingException { + Map expectedResponse = new HashMap<>(); + expectedResponse.put("1", "TestProject1"); + expectedResponse.put("2", "TestProject2"); + + mockWebServer.enqueue( + new MockResponse() + .setBody(new ObjectMapper().writeValueAsString(expectedResponse)) + .addHeader("Content-Type", "application/json") + ); + + Map response = projectClient.getProjectNames(); + + Map actualResponse = response.entrySet().stream() + .collect(Collectors.toMap(e -> String.valueOf(e.getKey()), Map.Entry::getValue)); + + assertEquals(expectedResponse, actualResponse); + } + + @Test + void testGetProjectNames_WhenServerError_ThrowsClientException() { + String errorBody = "Internal Server Error"; + + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(500)); + + Exception exception = assertThrows(ClientException.class, () -> projectClient.getProjectNames()); + assertTrue(exception.getMessage().contains(errorBody)); + } + + @Test + void testGetProject_WhenSuccess_ReturnsProjectTO() throws JsonProcessingException { + Integer projectId = 1; + ProjectTO expectedProjectTO = new ProjectTO(); + expectedProjectTO.setId(4); + expectedProjectTO.setName("testName"); + expectedProjectTO.setRampTime("1h"); + expectedProjectTO.setSimulationTime(60000L); + expectedProjectTO.setTerminationPolicy(TerminationPolicy.script); + expectedProjectTO.setWorkloadType(IncrementStrategy.increasing); + + mockWebServer.enqueue( + new MockResponse() + .setBody(new ObjectMapper().writeValueAsString(expectedProjectTO)) + .addHeader("Content-Type", "application/json") + ); + + ProjectTO actualProjectTO = projectClient.getProject(projectId); + + assertEquals(expectedProjectTO.getId(), actualProjectTO.getId()); + assertEquals(expectedProjectTO.getName(), actualProjectTO.getName()); + assertEquals(expectedProjectTO.getRampTime(), actualProjectTO.getRampTime()); + assertEquals(expectedProjectTO.getSimulationTime(), actualProjectTO.getSimulationTime()); + assertEquals(expectedProjectTO.getTerminationPolicy(), actualProjectTO.getTerminationPolicy()); + assertEquals(expectedProjectTO.getWorkloadType(), actualProjectTO.getWorkloadType()); + } + + @Test + void testGetProject_WhenServerError_ThrowsClientException() { + Integer projectId = 1; + String errorBody = "Internal Server Error"; + + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(500)); + + Exception exception = assertThrows(ClientException.class, + () -> projectClient.getProject(projectId)); + assertTrue(exception.getMessage().contains(errorBody)); + } + + @Test + void testCreateProject_WhenSuccess_ReturnsMap() throws JsonProcessingException { + AutomationRequest request = createAutomationRequest(); + Map expectedResponse = new HashMap<>(); + expectedResponse.put("ProjectId", "17"); + expectedResponse.put("status", "Created"); + + mockWebServer.enqueue( + new MockResponse() + .setBody(new ObjectMapper().writeValueAsString(expectedResponse)) + .addHeader("Content-Type", "application/json") + ); + + Map response = projectClient.createProject(request); + + assertEquals(expectedResponse, response); + } + + @Test + void testCreateProject_WhenServerError_ThrowsClientException() { + AutomationRequest request = createAutomationRequest(); + String errorBody = "Internal Server Error"; + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(500)); + + Exception exception = assertThrows(ClientException.class, () -> projectClient.createProject(request)); + assertTrue(exception.getMessage().contains(errorBody)); + } + + @Test + void testUpdateProject_WhenSuccess_ReturnsMap() throws JsonProcessingException { + AutomationRequest request = createAutomationRequest(); + Map expectedResponse = new HashMap<>(); + expectedResponse.put("ProjectId", "18"); + expectedResponse.put("status", "Created"); + + mockWebServer.enqueue( + new MockResponse() + .setBody(new ObjectMapper().writeValueAsString(expectedResponse)) + .addHeader("Content-Type", "application/json") + ); + + Map response = projectClient.updateProject(request); + + assertEquals(expectedResponse, response); + } + + @Test + void testUpdateProject_WhenServerError_ThrowsClientException() { + AutomationRequest request = createAutomationRequest(); + String errorBody = "Internal Server Error"; + + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(500)); + + Exception exception = assertThrows(ClientException.class, () -> projectClient.updateProject(request)); + assertTrue(exception.getMessage().contains(errorBody)); + } + + @Test + void testDownloadTestScriptForProject_WhenSuccess_ReturnsContentAsString() { + Integer projectId = 7; + String expectedResponse = "Script Content"; + + mockWebServer.enqueue(new MockResponse() + .setBody(expectedResponse) + .addHeader("Content-Type", "text/plain")); + + String actualResponse = projectClient.downloadTestScriptForProject(projectId); + + assertEquals(expectedResponse, actualResponse); + } + + @Test + void testDownloadTestScriptForProject_WhenServerError_ThrowsClientException() { + Integer projectId = 9; + String errorBody = "Internal Server Error"; + + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(500)); + + Exception exception = assertThrows(ClientException.class, () -> + projectClient.downloadTestScriptForProject(projectId) + ); + assertTrue(exception.getMessage().contains(errorBody)); + } + + @Test + void testDeleteProject_WhenSuccess_ReturnsString() { + Integer projectId = 11; + String expectedResponse = "Project deleted successfully"; + + mockWebServer.enqueue( + new MockResponse() + .setBody(expectedResponse) + .addHeader("Content-Type", "text/plain") + ); + + String response = projectClient.deleteProject(projectId); + System.out.println(response); + assertEquals(expectedResponse, response); + } + + @Test + void testDeleteProject_WhenServerError_ThrowsClientException() { + Integer projectId = 12; + String errorBody = "Internal Server Error"; + + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(500)); + + Exception exception = assertThrows(ClientException.class, + () -> projectClient.deleteProject(projectId) + ); + assertTrue(exception.getMessage().contains(errorBody)); + } + + private AutomationRequest createAutomationRequest() { + return AutomationRequest.builder() + .withProductName("Test Product") + .withRampTime("1920s") + .withSimulationTime("7200s") + .withUserIntervalIncrement(1) + .withAddedTestPlan(new AutomationTestPlan("Main",100,0, + new ArrayList<>(List.of(new AutomationScriptGroup("testScriptGroup", 0, 0, + new ArrayList<>(List.of(new AutomationScriptGroupStep(123, "testScript", 1, 0)))))))) + .build(); + } +} diff --git a/rest-mvc/src/test/java/com/intuit/tank/rest/mvc/rest/clients/ScriptClientTest.java b/rest-mvc/src/test/java/com/intuit/tank/rest/mvc/rest/clients/ScriptClientTest.java new file mode 100644 index 000000000..ba972d2cf --- /dev/null +++ b/rest-mvc/src/test/java/com/intuit/tank/rest/mvc/rest/clients/ScriptClientTest.java @@ -0,0 +1,452 @@ +package com.intuit.tank.rest.mvc.rest.clients; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.intuit.tank.project.ExternalScript; +import com.intuit.tank.project.Script; +import com.intuit.tank.project.ScriptStep; +import com.intuit.tank.rest.mvc.rest.clients.util.ClientException; +import com.intuit.tank.rest.mvc.rest.util.ScriptServiceUtil; +import com.intuit.tank.script.models.*; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.MockitoAnnotations; +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.core.io.buffer.DefaultDataBufferFactory; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.*; + +public class ScriptClientTest { + MockWebServer mockWebServer; + + ScriptClient scriptClient; + + @BeforeEach + void setUp() throws IOException { + MockitoAnnotations.openMocks(this); + mockWebServer = new MockWebServer(); + mockWebServer.start(); + String serviceUrl = mockWebServer.url("/").toString(); + scriptClient = new ScriptClient(serviceUrl, null, null); + } + + @AfterEach + void tearDown() throws IOException { + mockWebServer.shutdown(); + } + + @Test + void testScriptClientDefaultConstructor_SetsFieldsCorrectly() { + String serviceUrl = "http://localhost:8080"; + ScriptClient scriptClient = new ScriptClient(serviceUrl); + + assertEquals("/v2/scripts", scriptClient.getServiceBaseUrl()); + } + + @Test + void testGetScripts_WhenSuccess_ReturnsContainer() throws JsonProcessingException { + ScriptDescriptionContainer expectedResponse = createScriptDescriptionContainer(); + mockWebServer.enqueue( + new MockResponse() + .setBody(new ObjectMapper().writeValueAsString(expectedResponse)) + .addHeader("Content-Type", "application/json") + ); + ScriptDescriptionContainer response = scriptClient.getScripts(); + assertEquals(expectedResponse.getScripts().get(0).getName(), response.getScripts().get(0).getName()); + assertEquals(expectedResponse.getScripts().get(1).getName(), response.getScripts().get(1).getName()); + assertEquals(expectedResponse.getScripts().get(0).getRuntime(), response.getScripts().get(0).getRuntime()); + assertEquals(expectedResponse.getScripts().get(1).getRuntime(), response.getScripts().get(1).getRuntime()); + } + + @Test + void testGetScripts_WhenServerError_ThrowsClientException() { + String errorBody = "Internal Server Error"; + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(500)); + Exception exception = assertThrows(ClientException.class, () -> scriptClient.getScripts()); + assertTrue(exception.getMessage().contains(errorBody)); + } + + @Test + void testGetScript_WhenSuccess_ReturnsScriptTO() throws JsonProcessingException { + ScriptTO expectedResponse = createScriptTO(); + mockWebServer.enqueue( + new MockResponse() + .setBody(new ObjectMapper().writeValueAsString(expectedResponse)) + .addHeader("Content-Type", "application/json") + ); + ScriptTO response = scriptClient.getScript(expectedResponse.getId()); + + assertScriptTO(expectedResponse, response); + } + + @Test + void testGetScript_WhenServerError_ThrowsClientException() { + Integer scriptId = 1; + String errorBody = "Internal Server Error"; + + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(500)); + Exception exception = assertThrows(ClientException.class, () -> scriptClient.getScript(scriptId)); + + assertTrue(exception.getMessage().contains(errorBody)); + } + + @Test + void testCreateScript_WhenSuccess_ReturnsScriptTO() throws JsonProcessingException { + ScriptTO expectedResponse = createScriptTO(); + + mockWebServer.enqueue( + new MockResponse() + .setBody(new ObjectMapper().writeValueAsString(expectedResponse)) + .addHeader("Content-Type", "application/json") + ); + ScriptTO response = scriptClient.createScript(expectedResponse); + + assertScriptTO(expectedResponse, response); + } + + @Test + void testCreateScript_WhenServerError_ThrowsClientException() { + ScriptTO scriptTo = new ScriptTO(); + String errorBody = "Internal Server Error"; + + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(500)); + + Exception exception = assertThrows(ClientException.class, () -> scriptClient.createScript(scriptTo)); + assertTrue(exception.getMessage().contains(errorBody)); + } + + @Test + void testDownloadScript_WhenSuccess_ReturnsDataBuffer() { + Integer scriptId = 1; + String expectedContent = "Test Script Content"; + DefaultDataBufferFactory bufferFactory = new DefaultDataBufferFactory(); + DataBuffer expectedResponse = bufferFactory.wrap(expectedContent.getBytes()); + + mockWebServer.enqueue(new MockResponse() + .setBody(expectedContent) + .addHeader("Content-Type", "application/octet-stream")); + + DataBuffer response = scriptClient.downloadScript(scriptId).block(); + + assertEquals(expectedResponse.toString(StandardCharsets.UTF_8), response.toString(StandardCharsets.UTF_8)); + } + + @Test + void testDownloadScript_WhenServerError_ThrowsClientException() { + Integer scriptId = 92; + String errorBody = "Internal Server Error"; + + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(500)); + + Exception exception = assertThrows(ClientException.class, () -> scriptClient.downloadScript(scriptId).block()); + assertTrue(exception.getMessage().contains(errorBody)); + } + + @Test + void testDownloadHarnessScript_WhenSuccess_ReturnsString() { + Integer scriptId = 3; + String expectedResponse = "Test Script Content"; + + mockWebServer.enqueue(new MockResponse() + .setBody(expectedResponse) + .addHeader("Content-Type", "text/plain") + ); + + String response = scriptClient.downloadHarnessScript(scriptId); + assertEquals(expectedResponse, response); + } + + @Test + void testDownloadHarnessScript_WhenServerError_ThrowsClientException() { + Integer scriptId = 3; + String errorBody = "Internal Server Error"; + + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(500)); + + Exception exception = assertThrows(ClientException.class, + () -> scriptClient.downloadHarnessScript(scriptId) + ); + assertTrue(exception.getMessage().contains(errorBody)); + } + + @Test + void testUploadScript_WhenSuccess_ReturnsMap() throws JsonProcessingException { + String name = "uploadTest"; + int scriptId = 8; + MultipartFile file = new MockMultipartFile("file.txt", new byte[0]); + Map expectedResponse = new HashMap<>(); + expectedResponse.put("message", "Script with new script ID " + scriptId + " has been uploaded"); + + mockWebServer.enqueue( + new MockResponse() + .setBody(new ObjectMapper().writeValueAsString(expectedResponse)) + .addHeader("Content-Type", "application/json") + ); + + Map response = scriptClient.uploadScript(name, scriptId, file); + assertEquals(expectedResponse, response); + } + + @Test + void testUploadScript_WhenServerError_ThrowsClientException() { + String name = "uploadTest"; + Integer scriptId = 1; + MultipartFile file = new MockMultipartFile("file.txt", new byte[0]); + String errorBody = "Internal Server Error"; + + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(500)); + + Exception exception = assertThrows(ClientException.class, () -> + scriptClient.uploadScript(name, scriptId, file) + ); + assertTrue(exception.getMessage().contains(errorBody)); + } + + @Test + void testDeleteScript_WhenSuccess_ReturnsString() { + Integer scriptId = 1; + String expectedResponse = "Script deleted successfully"; + + mockWebServer.enqueue(new MockResponse() + .setBody(expectedResponse) + .addHeader("Content-Type", "text/plain") + ); + + String response = scriptClient.deleteScript(scriptId); + assertEquals(expectedResponse, response); + } + + @Test + void testDeleteScript_WhenServerError_ThrowsClientException() { + Integer scriptId = 1; + String errorBody = "Internal Server Error"; + + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(500)); + + Exception exception = assertThrows(ClientException.class, + () -> scriptClient.deleteScript(scriptId) + ); + assertTrue(exception.getMessage().contains(errorBody)); + } + + @Test + void testGetExternalScripts_WhenSuccess_ReturnsExternalScriptContainer() throws JsonProcessingException { + ExternalScriptContainer expectedResponse = createExternalScriptContainer(); + + mockWebServer.enqueue( + new MockResponse() + .setBody(new ObjectMapper().writeValueAsString(expectedResponse)) + .addHeader("Content-Type", "application/json") + ); + + ExternalScriptContainer response = scriptClient.getExternalScripts(); + assertEquals(expectedResponse.getScripts().get(0).getName(), response.getScripts().get(0).getName()); + assertEquals(expectedResponse.getScripts().get(1).getScript(), response.getScripts().get(1).getScript()); + } + + @Test + void testGetExternalScripts_WhenServerError_ThrowsClientException() { + String errorBody = "Internal Server Error"; + + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(500)); + Exception exception = assertThrows(ClientException.class, + () -> scriptClient.getExternalScripts() + ); + assertTrue(exception.getMessage().contains(errorBody)); + } + + @Test + void testGetExternalScript_WhenSuccess_ReturnsExternalScriptTO() throws JsonProcessingException { + Integer externalScriptId = 56; + ExternalScriptTO expectedResponse = createExternalScriptTO(); + + mockWebServer.enqueue( + new MockResponse() + .setBody(new ObjectMapper().writeValueAsString(expectedResponse)) + .addHeader("Content-Type", "application/json") + ); + + ExternalScriptTO response = scriptClient.getExternalScript(externalScriptId); + assertExternalScriptTO(expectedResponse, response); + } + + @Test + void testGetExternalScript_WhenServerError_ThrowsClientException() { + Integer externalScriptId = 58; + String errorBody = "Internal Server Error"; + + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(500)); + + Exception exception = assertThrows(ClientException.class, + () -> scriptClient.getExternalScript(externalScriptId) + ); + assertTrue(exception.getMessage().contains(errorBody)); + } + + @Test + void testCreateExternalScript_WhenSuccess_ReturnsExternalScriptTO() throws JsonProcessingException { + ExternalScriptTO scriptTo = createExternalScriptTO(); + ExternalScriptTO expectedResponse = createExternalScriptTO(); + + mockWebServer.enqueue( + new MockResponse() + .setBody(new ObjectMapper().writeValueAsString(expectedResponse)) + .addHeader("Content-Type", "application/json") + ); + + ExternalScriptTO response = scriptClient.createExternalScript(scriptTo); + assertExternalScriptTO(expectedResponse, response); + } + + @Test + void testCreateExternalScript_WhenServerError_ThrowsClientException() { + ExternalScriptTO scriptTo = createExternalScriptTO(); + String errorBody = "Internal Server Error"; + + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(500)); + + Exception exception = assertThrows(ClientException.class, + () -> scriptClient.createExternalScript(scriptTo) + ); + assertTrue(exception.getMessage().contains(errorBody)); + } + + @Test + void testDownloadExternalScript_WhenSuccess_ReturnsDataBuffer() { + Integer externalScriptId = 78; + String expectedContent = "Test External Script content"; + DefaultDataBufferFactory bufferFactory = new DefaultDataBufferFactory(); + DataBuffer expectedResponse = bufferFactory.wrap(expectedContent.getBytes()); + + mockWebServer.enqueue(new MockResponse() + .setBody(expectedContent) + .addHeader("Content-Type", "application/octet-stream")); + + DataBuffer response = scriptClient.downloadExternalScript(externalScriptId).block(); + + assertEquals(expectedResponse.toString(StandardCharsets.UTF_8), response.toString(StandardCharsets.UTF_8)); + } + + @Test + void testDownloadExternalScript_WhenServerError_ThrowsClientException() { + Integer externalScriptId = 34; + String errorBody = "Internal Server Error"; + + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(500)); + + Exception exception = assertThrows(ClientException.class, () -> + scriptClient.downloadExternalScript(externalScriptId).block() + ); + assertTrue(exception.getMessage().contains(errorBody)); + } + + @Test + void testDeleteExternalScript_WhenSuccess_ReturnsString() { + Integer externalScriptId = 24; + String expectedResponse = "External Script deleted successfully"; + + mockWebServer.enqueue(new MockResponse() + .setBody(expectedResponse) + .addHeader("Content-Type", "text/plain") + ); + + String response = scriptClient.deleteExternalScript(externalScriptId); + assertEquals(expectedResponse, response); + } + + @Test + void testDeleteExternalScript_WhenServerError_ThrowsClientException() { + Integer externalScriptId = 45; + String errorBody = "Internal Server Error"; + + mockWebServer.enqueue(new MockResponse().setBody(errorBody).setResponseCode(500)); + + Exception exception = assertThrows(ClientException.class, + () -> scriptClient.deleteExternalScript(externalScriptId) + ); + assertTrue(exception.getMessage().contains(errorBody)); + } + + + private ScriptTO createScriptTO() { + int scriptId = 19; + Script firstScript = new Script(); + firstScript.setId(scriptId); + firstScript.setName("testName"); + firstScript.setRuntime(5); + firstScript.setComments("testComments"); + firstScript.setProductName("testProductName"); + List steps = new ArrayList<>(); + ScriptStep step = new ScriptStep(); + step.setName("testStepName"); + steps.add(step); + firstScript.setSteps(steps); + return ScriptServiceUtil.scriptToTransferObject(firstScript); + } + + private ExternalScriptTO createExternalScriptTO() { + int externalScriptId = 20; + ExternalScript firstScript = new ExternalScript(); + firstScript.setId(externalScriptId); + firstScript.setName("testName"); + firstScript.setScript("testScript"); + firstScript.setProductName("testProductName"); + firstScript.setCreator("admin"); + firstScript.setCreated(new Date()); + return ScriptServiceUtil.externalScriptToTO(firstScript); + } + + private void assertScriptTO(ScriptTO expected, ScriptTO actual) { + assertEquals(expected.getId(), actual.getId()); + assertEquals(expected.getName(), actual.getName()); + assertEquals(expected.getRuntime(), actual.getRuntime()); + assertEquals(expected.getComments(), actual.getComments()); + assertEquals(expected.getProductName(), actual.getProductName()); + assertEquals(expected.getSteps().get(0).getName(), actual.getSteps().get(0).getName()); + } + + private void assertExternalScriptTO(ExternalScriptTO expected, ExternalScriptTO actual) { + assertEquals(expected.getId(), actual.getId()); + assertEquals(expected.getName(), actual.getName()); + assertEquals(expected.getScript(), actual.getScript()); + assertEquals(expected.getProductName(), actual.getProductName()); + assertEquals(expected.getCreator(), actual.getCreator()); + assertEquals(expected.getCreated(), actual.getCreated()); + } + + private ScriptDescriptionContainer createScriptDescriptionContainer() { + List