Skip to content

Commit

Permalink
Feature/add tosca app tests (#213)
Browse files Browse the repository at this point in the history
Signed-off-by: Marvin Bechtold <marvin.bechtold.dev@gmail.com>
  • Loading branch information
mar-be authored Mar 1, 2022
1 parent 338fbee commit 6570a32
Show file tree
Hide file tree
Showing 7 changed files with 1,020 additions and 20 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*******************************************************************************
* Copyright (c) 2022 the qc-atlas contributors.
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/

package org.planqk.atlas.core;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestTemplateConfiguration {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@

package org.planqk.atlas.core;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.InputMismatchException;

import org.apache.http.client.utils.URIBuilder;
import org.planqk.atlas.core.model.ToscaApplication;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
Expand Down Expand Up @@ -48,40 +51,47 @@
public class WineryService {

// API Endpoints
private final String baseAPIEndpoint;
private final URIBuilder baseAPIEndpoint;

private final ObjectMapper mapper = new ObjectMapper();

private final RestTemplate restTemplate;

public WineryService(
@Value("${org.planqk.atlas.winery.protocol}") String protocol,
@Value("${org.planqk.atlas.winery.hostname}") String hostname,
@Value("${org.planqk.atlas.winery.port}") String port
) {
@Value("${org.planqk.atlas.winery.port}") int port,
RestTemplate restTemplate) {
this.restTemplate = restTemplate;
this.baseAPIEndpoint = new URIBuilder();
this.baseAPIEndpoint.setHost(hostname).setPort(port);
if ("".equals(protocol)) {
this.baseAPIEndpoint = String.format("http://%s:%s/", hostname, port);
this.baseAPIEndpoint.setScheme("http");
} else {
this.baseAPIEndpoint = String.format("%s://%s:%s/", protocol, hostname, port);
this.baseAPIEndpoint.setScheme(protocol);
}
}

public String get(@NonNull String route) {
return this.get(route, String.class);
}

public <T> T get(String route, Class<T> responseType) {

final RestTemplate restTemplate = new RestTemplate();
public <T> T get(String route, Class<T> responseType) {
try {
final ResponseEntity<T> response = restTemplate.getForEntity(this.baseAPIEndpoint + route, responseType);
final ResponseEntity<T> response = restTemplate.getForEntity(this.baseAPIEndpoint.setPath(route).build(), responseType);
if (!response.getStatusCode().equals(HttpStatus.OK)) {
throw new ResponseStatusException(response.getStatusCode());
}
return response.getBody();
} catch (HttpClientErrorException.NotFound notFound) {
throw new ResponseStatusException(notFound.getStatusCode());
} catch (URISyntaxException e) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST);
}
}


public ToscaApplication uploadCsar(@NonNull Resource file, String name) {
final HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
Expand All @@ -90,18 +100,26 @@ public ToscaApplication uploadCsar(@NonNull Resource file, String name) {
body.add("name", name);
final HttpEntity<MultiValueMap<String, Object>> postRequestEntity = new HttpEntity<>(body, headers);

final RestTemplate restTemplate = new RestTemplate();
final ResponseEntity<String> response = restTemplate
.postForEntity(this.baseAPIEndpoint + "/winery/", postRequestEntity, String.class);
final ResponseEntity<String> response;
try {
response = this.restTemplate
.postForEntity(this.baseAPIEndpoint.setPath("/winery/").build(), postRequestEntity, String.class);
} catch (URISyntaxException e) {
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR);
}
if (!response.getStatusCode().equals(HttpStatus.CREATED)) {
throw new ResponseStatusException(response.getStatusCode());
}
if (response.getHeaders().getLocation() == null) {
final URI location = response.getHeaders().getLocation();
if (location == null) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND);
}
final String path = response.getHeaders().getLocation().getPath();
log.info(path);
final String jsonResponse = restTemplate.getForObject(this.baseAPIEndpoint + path, String.class);
final String jsonResponse;
try {
jsonResponse = this.restTemplate.getForObject(baseAPIEndpoint.setPath(location.getPath()).build(), String.class);
} catch (URISyntaxException e) {
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR);
}
final JsonNode node;
try {
node = this.mapper.readTree(jsonResponse).get("serviceTemplateOrNodeTypeOrNodeTypeImplementation");
Expand All @@ -114,7 +132,7 @@ public ToscaApplication uploadCsar(@NonNull Resource file, String name) {
toscaApplication.setToscaNamespace(firstElement.get("targetNamespace").asText());
toscaApplication.setToscaName(firstElement.get("name").asText());
toscaApplication.setName(name);
toscaApplication.setWineryLocation(path);
toscaApplication.setWineryLocation(location.getPath());
return toscaApplication;
} catch (JsonProcessingException e) {
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR);
Expand All @@ -123,8 +141,13 @@ public ToscaApplication uploadCsar(@NonNull Resource file, String name) {

public void delete(@NonNull ToscaApplication toscaApplication) {
final String path = toscaApplication.getWineryLocation();
final RestTemplate restTemplate = new RestTemplate();
restTemplate.delete(this.baseAPIEndpoint + path);
try {
this.restTemplate.delete(this.baseAPIEndpoint.setPath(path).build());
} catch (URISyntaxException e) {
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR);
}
}


}

Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
/*******************************************************************************
* Copyright (c) 2022 the qc-atlas contributors.
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/

package org.planqk.atlas.core;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.nio.charset.StandardCharsets;

import lombok.SneakyThrows;
import org.apache.http.client.utils.URIBuilder;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.junit.jupiter.MockitoExtension;
import org.planqk.atlas.core.model.ToscaApplication;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.server.ResponseStatusException;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.eq;

@ExtendWith(MockitoExtension.class)
@RunWith(MockitoJUnitRunner.class)
class WineryServiceTest {

@Mock
private RestTemplate restTemplate;

private WineryService wineryService;

private URIBuilder wineryEndPoint;

@BeforeEach
void init(){
wineryService = new WineryService("http", "localhost", 8091, restTemplate);
wineryEndPoint = new URIBuilder();
wineryEndPoint.setScheme("http").setHost("localhost").setPort(8091);
}

@SneakyThrows
@Test
public void get_returnOK() {
var testRoute = "this/is/the/test/route";
var expectedResult = "Test-Body";
Mockito.when(restTemplate.getForEntity(eq(wineryEndPoint.setPath(testRoute).build()), eq(String.class))).thenReturn(new ResponseEntity<>(expectedResult, HttpStatus.OK));
String result = wineryService.get(testRoute);
assertEquals(expectedResult, result);
}

@SneakyThrows
@Test
public void get_notFound() {
var testRoute = "this/is/the/test/route";
Mockito.when(restTemplate.getForEntity(eq(wineryEndPoint.setPath(testRoute).build()), eq(String.class))).thenReturn(new ResponseEntity<>(HttpStatus.NOT_FOUND));
ResponseStatusException responseStatusException = assertThrows(ResponseStatusException.class, () -> wineryService.get(testRoute));
assertEquals(HttpStatus.NOT_FOUND, responseStatusException.getStatus());
}

@Test
@SneakyThrows
public void uploadCsar_notFound(){
var uploadRoute = "/winery/";
Resource file = new InputStreamResource(new ByteArrayInputStream("test input stream".getBytes()));
String name = "test-name";

final HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
final MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
body.add("file", file);
body.add("name", name);
final HttpEntity<MultiValueMap<String, Object>> postRequestEntity = new HttpEntity<>(body, headers);

Mockito.when(restTemplate.postForEntity(eq(wineryEndPoint.setPath(uploadRoute).build()), eq(postRequestEntity), eq(String.class))).thenReturn(new ResponseEntity<>(HttpStatus.NOT_FOUND));
ResponseStatusException responseStatusException = assertThrows(ResponseStatusException.class, () -> wineryService.uploadCsar(file, name));
assertEquals(HttpStatus.NOT_FOUND, responseStatusException.getStatus());
}

@Test
@SneakyThrows
public void uploadCsar_created(){
var uploadRoute = "/winery/";
var locationRoute = "/this/is/the/serviceTemplate/location";
Resource file = new InputStreamResource(new ByteArrayInputStream("test input stream".getBytes()));
String name = "test-name";

InputStream resourceAsStream = getClass().getClassLoader().getResourceAsStream("winery_response.json");
assert resourceAsStream != null;
String wineryJsonResponse = new String(resourceAsStream.readAllBytes(), StandardCharsets.UTF_8);


ToscaApplication expectedToscaApplication = new ToscaApplication();
expectedToscaApplication.setToscaID("Java_Web_Application__MySQL");
expectedToscaApplication.setToscaName("Java_Web_Application__MySQL");
expectedToscaApplication.setToscaNamespace("http://opentosca.org/servicetemplates");
expectedToscaApplication.setName(name);
expectedToscaApplication.setWineryLocation(locationRoute);

final HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
final MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
body.add("file", file);
body.add("name", name);
final HttpEntity<MultiValueMap<String, Object>> postRequestEntity = new HttpEntity<>(body, headers);


ResponseEntity<String> responseEntity = ResponseEntity.created(new URI(locationRoute)).build();

Mockito.when(restTemplate.postForEntity(eq(wineryEndPoint.setPath(uploadRoute).build()), eq(postRequestEntity), eq(String.class))).thenReturn(responseEntity);
Mockito.when(restTemplate.getForObject(eq(wineryEndPoint.setPath(locationRoute).build()), eq(String.class))).thenReturn(wineryJsonResponse);

ToscaApplication toscaApplication = wineryService.uploadCsar(file, name);
assertEquals(expectedToscaApplication, toscaApplication);
}

@SneakyThrows
@Test
public void delete() {
var wineryLocation = "this/is/the/winery/location";
ToscaApplication toscaApplication = new ToscaApplication();
toscaApplication.setWineryLocation(wineryLocation);
wineryService.delete(toscaApplication);
Mockito.verify(restTemplate).delete(wineryEndPoint.setPath(wineryLocation).build());
}


}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
################################################################################
# Copyright (c) 2020 the qc-atlas contributors.
# Copyright (c) 2020-2022 the qc-atlas contributors.
#
# See the NOTICE file(s) distributed with this work for additional
# information regarding copyright ownership.
Expand All @@ -17,3 +17,6 @@
# limitations under the License.
#################################################################################
cloud.storage.implementation-files-bucket-name=${IMPLEMENTATION_FILES_BUCKET_NAME:planqk-algo-artifacts}
org.planqk.atlas.winery.protocol=http
org.planqk.atlas.winery.hostname=localhost
org.planqk.atlas.winery.port=8080
Loading

0 comments on commit 6570a32

Please sign in to comment.