Skip to content
Snippets Groups Projects
Commit b852387d authored by Martin Weise's avatar Martin Weise
Browse files

add integration test for postgres service

parent 3b957dd7
No related branches found
No related tags found
2 merge requests!81New stable release,!43Merge dev to master
Showing
with 397 additions and 86 deletions
...@@ -160,6 +160,7 @@ services: ...@@ -160,6 +160,7 @@ services:
ports: ports:
- 9094:9094 - 9094:9094
volumes: volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /tmp:/tmp - /tmp:/tmp
links: links:
- fda-metadata-db - fda-metadata-db
......
...@@ -181,7 +181,9 @@ ...@@ -181,7 +181,9 @@
<exclude>at/tuwien/mapper/**/*</exclude> <exclude>at/tuwien/mapper/**/*</exclude>
<exclude>at/tuwien/exception/**/*</exclude> <exclude>at/tuwien/exception/**/*</exclude>
<exclude>at/tuwien/utils/**/*</exclude> <exclude>at/tuwien/utils/**/*</exclude>
<exclude>at/tuwien/config/**/*</exclude>
<exclude>**/FdaTableServiceApplication.class</exclude> <exclude>**/FdaTableServiceApplication.class</exclude>
<exclude>**/JdbcConnector.class</exclude>
</excludes> </excludes>
</configuration> </configuration>
<executions> <executions>
......
...@@ -55,7 +55,7 @@ public class TableEndpoint { ...@@ -55,7 +55,7 @@ public class TableEndpoint {
} }
@PostMapping("/table") @PostMapping("/table")
@ApiOperation(value = "Create a table", notes = "Creates a new table for a database, requires a running container. For the colum definition use the following example: [{\"name\": \"Ticker Symbol\", \"primaryKey\": true, \"type\": \"STRING\", \"nullAllowed\": false, \"checkExpression\": null, \"foreignKey\": null},{\"name\": \"Accounts Payable\", \"primaryKey\": false, \"type\": \"NUMBER\", \"nullAllowed\": false, \"checkExpression\": \"Accounts Payable > 0\", \"foreignKey\": null},{\"name\": \"Company\", \"primaryKey\": false, \"type\": \"STRING\", \"nullAllowed\": false, \"checkExpression\": null, \"foreignKey\": null}]") @ApiOperation(value = "Create a table", notes = "Creates a new table for a database, requires a running container.")
@ApiResponses({ @ApiResponses({
@ApiResponse(code = 201, message = "The table was created."), @ApiResponse(code = 201, message = "The table was created."),
@ApiResponse(code = 400, message = "The creation form contains invalid data."), @ApiResponse(code = 400, message = "The creation form contains invalid data."),
...@@ -65,9 +65,10 @@ public class TableEndpoint { ...@@ -65,9 +65,10 @@ public class TableEndpoint {
@ApiResponse(code = 409, message = "The container image is not supported."), @ApiResponse(code = 409, message = "The container image is not supported."),
@ApiResponse(code = 422, message = "The ."), @ApiResponse(code = 422, message = "The ."),
}) })
public ResponseEntity<TableBriefDto> create(@PathVariable("id") Long databaseId, @RequestBody TableCreateDto createDto) public ResponseEntity<TableBriefDto> create(@PathVariable("id") Long databaseId,
@RequestBody TableCreateDto createDto)
throws ImageNotSupportedException, DatabaseConnectionException, TableMalformedException, throws ImageNotSupportedException, DatabaseConnectionException, TableMalformedException,
DatabaseNotFoundException { DatabaseNotFoundException, DataProcessingException {
final Table table = tableService.create(databaseId, createDto); final Table table = tableService.create(databaseId, createDto);
return ResponseEntity.status(HttpStatus.CREATED) return ResponseEntity.status(HttpStatus.CREATED)
.body(tableMapper.tableToTableBriefDto(table)); .body(tableMapper.tableToTableBriefDto(table));
...@@ -80,7 +81,8 @@ public class TableEndpoint { ...@@ -80,7 +81,8 @@ public class TableEndpoint {
@ApiResponse(code = 401, message = "Not authorized to list all tables."), @ApiResponse(code = 401, message = "Not authorized to list all tables."),
@ApiResponse(code = 404, message = "Table not found in metadata database."), @ApiResponse(code = 404, message = "Table not found in metadata database."),
}) })
public ResponseEntity<TableDto> findById(@PathVariable("id") Long databaseId, @PathVariable("tableId") Long tableId) throws TableNotFoundException { public ResponseEntity<TableDto> findById(@PathVariable("id") Long databaseId, @PathVariable("tableId") Long tableId)
throws TableNotFoundException {
final Table table = tableService.findById(databaseId, tableId); final Table table = tableService.findById(databaseId, tableId);
return ResponseEntity.ok(tableMapper.tableToTableDto(table)); return ResponseEntity.ok(tableMapper.tableToTableDto(table));
} }
...@@ -93,7 +95,8 @@ public class TableEndpoint { ...@@ -93,7 +95,8 @@ public class TableEndpoint {
@ApiResponse(code = 401, message = "Not authorized to update tables."), @ApiResponse(code = 401, message = "Not authorized to update tables."),
@ApiResponse(code = 404, message = "The table is not found in database."), @ApiResponse(code = 404, message = "The table is not found in database."),
}) })
public ResponseEntity<TableBriefDto> update(@PathVariable("id") Long databaseId, @PathVariable("tableId") Long tableId) { public ResponseEntity<TableBriefDto> update(@PathVariable("id") Long databaseId,
@PathVariable("tableId") Long tableId) {
// TODO // TODO
return ResponseEntity.unprocessableEntity().body(new TableBriefDto()); return ResponseEntity.unprocessableEntity().body(new TableBriefDto());
} }
...@@ -106,7 +109,9 @@ public class TableEndpoint { ...@@ -106,7 +109,9 @@ public class TableEndpoint {
@ApiResponse(code = 404, message = "The table is not found in database."), @ApiResponse(code = 404, message = "The table is not found in database."),
}) })
@ResponseStatus(HttpStatus.OK) @ResponseStatus(HttpStatus.OK)
public void delete(@PathVariable("id") Long databaseId, @PathVariable("tableId") Long tableId) throws TableNotFoundException, DatabaseConnectionException, TableMalformedException { public void delete(@PathVariable("id") Long databaseId, @PathVariable("tableId") Long tableId)
throws TableNotFoundException, DatabaseConnectionException, TableMalformedException,
DataProcessingException {
tableService.delete(databaseId, tableId); tableService.delete(databaseId, tableId);
} }
...@@ -120,7 +125,9 @@ public class TableEndpoint { ...@@ -120,7 +125,9 @@ public class TableEndpoint {
@ApiResponse(code = 422, message = "The csv was not processible."), @ApiResponse(code = 422, message = "The csv was not processible."),
}) })
/* FIXME: this should be in a different endpoint */ /* FIXME: this should be in a different endpoint */
public ResponseEntity<QueryResultDto> insert(@PathVariable("id") Long databaseId, @PathVariable("tableId") Long tableId, @RequestParam("file") MultipartFile file) throws Exception { public ResponseEntity<QueryResultDto> insert(@PathVariable("id") Long databaseId,
@PathVariable("tableId") Long tableId,
@RequestParam("file") MultipartFile file) throws Exception {
final QueryResultDto queryResult = tableService.insert(databaseId, tableId, file); final QueryResultDto queryResult = tableService.insert(databaseId, tableId, file);
return ResponseEntity.ok(queryResultMapper.queryResultToQueryResultDto(queryResult)); return ResponseEntity.ok(queryResultMapper.queryResultToQueryResultDto(queryResult));
} }
...@@ -132,8 +139,10 @@ public class TableEndpoint { ...@@ -132,8 +139,10 @@ public class TableEndpoint {
@ApiResponse(code = 401, message = "Not authorized to list all tables."), @ApiResponse(code = 401, message = "Not authorized to list all tables."),
}) })
/* FIXME: this should be a different endpoint */ /* FIXME: this should be a different endpoint */
public ResponseEntity<QueryResultDto> showData(@PathVariable("id") Long databaseId, @PathVariable("tableId") Long tableId) public ResponseEntity<QueryResultDto> showData(@PathVariable("id") Long databaseId,
throws DatabaseNotFoundException, ImageNotSupportedException, TableNotFoundException, DatabaseConnectionException { @PathVariable("tableId") Long tableId)
throws DatabaseNotFoundException, ImageNotSupportedException, TableNotFoundException,
DatabaseConnectionException, DataProcessingException {
final QueryResultDto queryResult = tableService.showData(databaseId, tableId); final QueryResultDto queryResult = tableService.showData(databaseId, tableId);
return ResponseEntity.ok(queryResultMapper.queryResultToQueryResultDto(queryResult)); return ResponseEntity.ok(queryResultMapper.queryResultToQueryResultDto(queryResult));
} }
......
...@@ -7,6 +7,7 @@ import at.tuwien.entities.container.image.ContainerImage; ...@@ -7,6 +7,7 @@ import at.tuwien.entities.container.image.ContainerImage;
import at.tuwien.entities.container.image.ContainerImageEnvironmentItem; import at.tuwien.entities.container.image.ContainerImageEnvironmentItem;
import at.tuwien.entities.database.Database; import at.tuwien.entities.database.Database;
import at.tuwien.entities.database.table.Table; import at.tuwien.entities.database.table.Table;
import at.tuwien.entities.database.table.columns.TableColumn;
import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.TestPropertySource;
import java.time.Instant; import java.time.Instant;
...@@ -22,6 +23,11 @@ public abstract class BaseUnitTest { ...@@ -22,6 +23,11 @@ public abstract class BaseUnitTest {
public final static String DATABASE_1_INTERNALNAME = "nyse"; public final static String DATABASE_1_INTERNALNAME = "nyse";
public final static String TABLE_1_DESCRIPTION = "New York Stock Exchange"; public final static String TABLE_1_DESCRIPTION = "New York Stock Exchange";
public final static Long DATABASE_2_ID = 2L;
public final static String DATABASE_2_NAME = "RIVER";
public final static String DATABASE_2_INTERNALNAME = "river";
public final static String TABLE_2_DESCRIPTION = "River Data";
public final static Long TABLE_1_ID = 1L; public final static Long TABLE_1_ID = 1L;
public final static String TABLE_1_NAME = "Stock Exchange"; public final static String TABLE_1_NAME = "Stock Exchange";
public final static String TABLE_1_INTERNALNAME = "stock_exchange"; public final static String TABLE_1_INTERNALNAME = "stock_exchange";
...@@ -29,26 +35,35 @@ public abstract class BaseUnitTest { ...@@ -29,26 +35,35 @@ public abstract class BaseUnitTest {
public final static Long COLUMN_1_ID = 1L; public final static Long COLUMN_1_ID = 1L;
public final static Boolean COLUMN_1_PRIMARY = true; public final static Boolean COLUMN_1_PRIMARY = true;
public final static String COLUMN_1_NAME = "Min"; public final static String COLUMN_1_NAME = "Min";
public final static String COLUMN_1_INTERNAL_NAME = "min";
public final static ColumnTypeDto COLUMN_1_TYPE = ColumnTypeDto.NUMBER; public final static ColumnTypeDto COLUMN_1_TYPE = ColumnTypeDto.NUMBER;
public final static Boolean COLUMN_1_NULL = false; public final static Boolean COLUMN_1_NULL = false;
public final static Long COLUMN_2_ID = 2L; public final static Long COLUMN_2_ID = 2L;
public final static Boolean COLUMN_2_PRIMARY = false; public final static Boolean COLUMN_2_PRIMARY = false;
public final static String COLUMN_2_NAME = "Max"; public final static String COLUMN_2_NAME = "Max";
public final static String COLUMN_2_INTERNAL_NAME = "max";
public final static ColumnTypeDto COLUMN_2_TYPE = ColumnTypeDto.NUMBER; public final static ColumnTypeDto COLUMN_2_TYPE = ColumnTypeDto.NUMBER;
public final static Boolean COLUMN_2_NULL = true; public final static Boolean COLUMN_2_NULL = true;
public final static Long COLUMN_3_ID = 3L; public final static Long COLUMN_3_ID = 3L;
public final static Boolean COLUMN_3_PRIMARY = false; public final static Boolean COLUMN_3_PRIMARY = false;
public final static String COLUMN_3_NAME = "Buy"; public final static String COLUMN_3_NAME = "Buy";
public final static String COLUMN_3_INTERNAL_NAME = "buy";
public final static ColumnTypeDto COLUMN_3_TYPE = ColumnTypeDto.NUMBER; public final static ColumnTypeDto COLUMN_3_TYPE = ColumnTypeDto.NUMBER;
public final static Boolean COLUMN_3_NULL = true; public final static Boolean COLUMN_3_NULL = true;
public final static Long COLUMN_4_ID = 4L; public final static Long COLUMN_4_ID = 4L;
public final static Boolean COLUMN_4_PRIMARY = false; public final static Boolean COLUMN_4_PRIMARY = false;
public final static String COLUMN_4_NAME = "Sell"; public final static String COLUMN_4_NAME = "Sell";
public final static String COLUMN_4_INTERNAL_NAME = "sell";
public final static ColumnTypeDto COLUMN_4_TYPE = ColumnTypeDto.NUMBER; public final static ColumnTypeDto COLUMN_4_TYPE = ColumnTypeDto.NUMBER;
public final static Boolean COLUMN_4_NULL = true; public final static Boolean COLUMN_4_NULL = true;
public final static Long COLUMN_5_ID = 5L; public final static Long COLUMN_5_ID = 5L;
public final static Boolean COLUMN_5_PRIMARY = false; public final static Boolean COLUMN_5_PRIMARY = false;
public final static String COLUMN_5_NAME = "Description"; public final static String COLUMN_5_NAME = "Description";
public final static String COLUMN_5_INTERNAL_NAME = "description";
public final static ColumnTypeDto COLUMN_5_TYPE = ColumnTypeDto.TEXT; public final static ColumnTypeDto COLUMN_5_TYPE = ColumnTypeDto.TEXT;
public final static Boolean COLUMN_5_NULL = true; public final static Boolean COLUMN_5_NULL = true;
...@@ -69,6 +84,9 @@ public abstract class BaseUnitTest { ...@@ -69,6 +84,9 @@ public abstract class BaseUnitTest {
.value("postgres") .value("postgres")
.build()); .build());
public final static List<String> IMAGE_1_ENVIRONMENT = List.of("POSTGRES_USER=postgres",
"POSTGRES_PASSWORD=postgres", "POSTGRES_DB=" + DATABASE_1_INTERNALNAME);
public final static ContainerImage IMAGE_1 = ContainerImage.builder() public final static ContainerImage IMAGE_1 = ContainerImage.builder()
.id(IMAGE_1_ID) .id(IMAGE_1_ID)
.repository(IMAGE_1_REPOSITORY) .repository(IMAGE_1_REPOSITORY)
...@@ -81,14 +99,18 @@ public abstract class BaseUnitTest { ...@@ -81,14 +99,18 @@ public abstract class BaseUnitTest {
.build(); .build();
public final static Long CONTAINER_1_ID = 1L; public final static Long CONTAINER_1_ID = 1L;
public final static String CONTAINER_1_HASH = "deadbeef"; public static String CONTAINER_1_HASH = "deadbeef";
public final static ContainerImage CONTAINER_1_IMAGE = IMAGE_1; public final static ContainerImage CONTAINER_1_IMAGE = IMAGE_1;
public final static String CONTAINER_1_NAME = "u01"; public final static String CONTAINER_1_NAME = "u01";
public final static String CONTAINER_1_INTERNALNAME = "localhost"; public final static String CONTAINER_1_INTERNALNAME = "localhost";
public final static String CONTAINER_1_DATABASE = "univie";
public final static String CONTAINER_1_IP = "231.145.98.83";
public final static Instant CONTAINER_1_CREATED = Instant.now().minus(1, HOURS); public final static Instant CONTAINER_1_CREATED = Instant.now().minus(1, HOURS);
public final static Long CONTAINER_2_ID = 2L;
public final static String CONTAINER_2_HASH = "deadbeef";
public final static String CONTAINER_2_NAME = "u02";
public final static String CONTAINER_2_INTERNALNAME = "not3x1st1ng";
public final static Instant CONTAINER_2_CREATED = Instant.now().minus(1, HOURS);
public final static Container CONTAINER_1 = Container.builder() public final static Container CONTAINER_1 = Container.builder()
.id(CONTAINER_1_ID) .id(CONTAINER_1_ID)
.name(CONTAINER_1_NAME) .name(CONTAINER_1_NAME)
...@@ -98,12 +120,73 @@ public abstract class BaseUnitTest { ...@@ -98,12 +120,73 @@ public abstract class BaseUnitTest {
.containerCreated(CONTAINER_1_CREATED) .containerCreated(CONTAINER_1_CREATED)
.build(); .build();
public final static Container CONTAINER_2 = Container.builder()
.id(CONTAINER_2_ID)
.name(CONTAINER_2_NAME)
.internalName(CONTAINER_2_INTERNALNAME)
.image(CONTAINER_1_IMAGE)
.hash(CONTAINER_2_HASH)
.containerCreated(CONTAINER_2_CREATED)
.build();
public final static List<TableColumn> TABLE_1_COLUMNS = List.of(TableColumn.builder()
.id(COLUMN_1_ID)
.cdbid(DATABASE_1_ID)
.tid(TABLE_1_ID)
.name(COLUMN_1_NAME)
.internalName(COLUMN_1_INTERNAL_NAME)
.columnType(COLUMN_1_TYPE.name())
.isNullAllowed(COLUMN_1_NULL)
.isPrimaryKey(COLUMN_1_PRIMARY)
.build(),
TableColumn.builder()
.id(COLUMN_2_ID)
.cdbid(DATABASE_1_ID)
.tid(TABLE_1_ID)
.name(COLUMN_2_NAME)
.internalName(COLUMN_2_INTERNAL_NAME)
.columnType(COLUMN_2_TYPE.name())
.isNullAllowed(COLUMN_2_NULL)
.isPrimaryKey(COLUMN_2_PRIMARY)
.build(),
TableColumn.builder()
.id(COLUMN_3_ID)
.cdbid(DATABASE_1_ID)
.tid(TABLE_1_ID)
.name(COLUMN_3_NAME)
.internalName(COLUMN_3_INTERNAL_NAME)
.columnType(COLUMN_3_TYPE.name())
.isNullAllowed(COLUMN_3_NULL)
.isPrimaryKey(COLUMN_3_PRIMARY)
.build(),
TableColumn.builder()
.id(COLUMN_4_ID)
.cdbid(DATABASE_1_ID)
.tid(TABLE_1_ID)
.name(COLUMN_4_NAME)
.internalName(COLUMN_4_INTERNAL_NAME)
.columnType(COLUMN_4_TYPE.name())
.isNullAllowed(COLUMN_4_NULL)
.isPrimaryKey(COLUMN_4_PRIMARY)
.build(),
TableColumn.builder()
.id(COLUMN_5_ID)
.cdbid(DATABASE_1_ID)
.tid(TABLE_1_ID)
.name(COLUMN_5_NAME)
.internalName(COLUMN_5_INTERNAL_NAME)
.columnType(COLUMN_5_TYPE.name())
.isNullAllowed(COLUMN_5_NULL)
.isPrimaryKey(COLUMN_5_PRIMARY)
.build());
public final static Table TABLE_1 = Table.builder() public final static Table TABLE_1 = Table.builder()
.id(TABLE_1_ID) .id(TABLE_1_ID)
.created(Instant.now()) .created(Instant.now())
.internalName(TABLE_1_INTERNALNAME) .internalName(TABLE_1_INTERNALNAME)
.name(TABLE_1_NAME) .name(TABLE_1_NAME)
.lastModified(Instant.now()) .lastModified(Instant.now())
.columns(TABLE_1_COLUMNS)
.tdbid(DATABASE_1_ID) .tdbid(DATABASE_1_ID)
.build(); .build();
...@@ -117,6 +200,17 @@ public abstract class BaseUnitTest { ...@@ -117,6 +200,17 @@ public abstract class BaseUnitTest {
.internalName(DATABASE_1_INTERNALNAME) .internalName(DATABASE_1_INTERNALNAME)
.build(); .build();
/* no connection */
public final static Database DATABASE_2 = Database.builder()
.id(DATABASE_2_ID)
.created(Instant.now().minus(1, HOURS))
.lastModified(Instant.now())
.isPublic(false)
.name(DATABASE_2_NAME)
.container(CONTAINER_2)
.internalName(DATABASE_2_INTERNALNAME)
.build();
public final static ColumnCreateDto[] COLUMNS5 = new ColumnCreateDto[]{ public final static ColumnCreateDto[] COLUMNS5 = new ColumnCreateDto[]{
ColumnCreateDto.builder() ColumnCreateDto.builder()
.type(COLUMN_1_TYPE) .type(COLUMN_1_TYPE)
...@@ -149,4 +243,6 @@ public abstract class BaseUnitTest { ...@@ -149,4 +243,6 @@ public abstract class BaseUnitTest {
.primaryKey(COLUMN_5_PRIMARY) .primaryKey(COLUMN_5_PRIMARY)
.build()}; .build()};
public final static String COLUMNS5_CREATE = "CREATE TABLE " + TABLE_1_INTERNALNAME + "(Min INTEGER NOT NULL PRIMARY KEY,Max INTEGER NULL,Buy INTEGER NULL,Sell INTEGER NULL,Description TEXT NULL);";
} }
...@@ -60,7 +60,7 @@ public class TableEndpointUnitTest extends BaseUnitTest { ...@@ -60,7 +60,7 @@ public class TableEndpointUnitTest extends BaseUnitTest {
@Test @Test
public void create_succeeds() throws DatabaseConnectionException, TableMalformedException, public void create_succeeds() throws DatabaseConnectionException, TableMalformedException,
DatabaseNotFoundException, ImageNotSupportedException, TableNotFoundException { DatabaseNotFoundException, ImageNotSupportedException, TableNotFoundException, DataProcessingException {
final TableCreateDto request = TableCreateDto.builder() final TableCreateDto request = TableCreateDto.builder()
.name(TABLE_1_NAME) .name(TABLE_1_NAME)
.description(TABLE_1_DESCRIPTION) .description(TABLE_1_DESCRIPTION)
...@@ -78,7 +78,7 @@ public class TableEndpointUnitTest extends BaseUnitTest { ...@@ -78,7 +78,7 @@ public class TableEndpointUnitTest extends BaseUnitTest {
@Test @Test
public void create_databaseNotFound_fails() throws DatabaseConnectionException, TableMalformedException, public void create_databaseNotFound_fails() throws DatabaseConnectionException, TableMalformedException,
DatabaseNotFoundException, ImageNotSupportedException { DatabaseNotFoundException, ImageNotSupportedException, DataProcessingException {
final TableCreateDto request = TableCreateDto.builder() final TableCreateDto request = TableCreateDto.builder()
.name(TABLE_1_NAME) .name(TABLE_1_NAME)
.description(TABLE_1_DESCRIPTION) .description(TABLE_1_DESCRIPTION)
...@@ -97,7 +97,7 @@ public class TableEndpointUnitTest extends BaseUnitTest { ...@@ -97,7 +97,7 @@ public class TableEndpointUnitTest extends BaseUnitTest {
@Test @Test
public void create_tableNotFound_fails() throws DatabaseConnectionException, TableMalformedException, public void create_tableNotFound_fails() throws DatabaseConnectionException, TableMalformedException,
DatabaseNotFoundException, ImageNotSupportedException { DatabaseNotFoundException, ImageNotSupportedException, DataProcessingException {
final TableCreateDto request = TableCreateDto.builder() final TableCreateDto request = TableCreateDto.builder()
.name(TABLE_1_NAME) .name(TABLE_1_NAME)
.description(TABLE_1_DESCRIPTION) .description(TABLE_1_DESCRIPTION)
...@@ -183,7 +183,8 @@ public class TableEndpointUnitTest extends BaseUnitTest { ...@@ -183,7 +183,8 @@ public class TableEndpointUnitTest extends BaseUnitTest {
} }
@Test @Test
public void delete_notFound_fails() throws TableNotFoundException, DatabaseConnectionException, TableMalformedException { public void delete_notFound_fails() throws TableNotFoundException, DatabaseConnectionException,
TableMalformedException, DataProcessingException {
doThrow(TableNotFoundException.class) doThrow(TableNotFoundException.class)
.when(tableService) .when(tableService)
.delete(DATABASE_1_ID, TABLE_1_ID); .delete(DATABASE_1_ID, TABLE_1_ID);
...@@ -195,7 +196,8 @@ public class TableEndpointUnitTest extends BaseUnitTest { ...@@ -195,7 +196,8 @@ public class TableEndpointUnitTest extends BaseUnitTest {
} }
@Test @Test
public void delete_succeeds() throws TableNotFoundException, DatabaseConnectionException, TableMalformedException { public void delete_succeeds() throws TableNotFoundException, DatabaseConnectionException, TableMalformedException,
DataProcessingException {
/* test */ /* test */
tableEndpoint.delete(DATABASE_1_ID, TABLE_1_ID); tableEndpoint.delete(DATABASE_1_ID, TABLE_1_ID);
} }
......
package at.tuwien.service;
import at.tuwien.BaseUnitTest;
import at.tuwien.api.database.table.TableCreateDto;
import at.tuwien.exception.DataProcessingException;
import at.tuwien.exception.DatabaseConnectionException;
import at.tuwien.exception.TableMalformedException;
import at.tuwien.exception.TableNotFoundException;
import at.tuwien.mapper.TableMapper;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.command.CreateContainerResponse;
import com.github.dockerjava.api.exception.NotModifiedException;
import com.github.dockerjava.api.model.HostConfig;
import com.github.dockerjava.api.model.PortBinding;
import com.netflix.discovery.converters.Auto;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.*;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.*;
@SpringBootTest
@ExtendWith(SpringExtension.class)
public class PostgresIntegrationTest extends BaseUnitTest {
@Autowired
private PostgresService postgresService;
@Autowired
private TableMapper tableMapper;
@Autowired
private Properties postgresProperties;
@Autowired
private HostConfig hostConfig;
@Autowired
private DockerClient dockerClient;
@BeforeEach
public void beforeEach() throws InterruptedException {
afterEach();
/* create container */
final CreateContainerResponse request = dockerClient.createContainerCmd("postgres:latest")
.withEnv(IMAGE_1_ENVIRONMENT)
.withHostConfig(hostConfig.withNetworkMode("bridge")
.withPortBindings(PortBinding.parse("5433:5432")))
.withName(CONTAINER_1_INTERNALNAME)
.withHostName(CONTAINER_1_INTERNALNAME)
.exec();
System.out.println("CREATE CONTAINER " + CONTAINER_1_INTERNALNAME);
/* start container */
dockerClient.startContainerCmd(request.getId()).exec();
System.out.println("START CONTAINER " + CONTAINER_1_INTERNALNAME);
CONTAINER_1_HASH = request.getId();
CONTAINER_1.setHash(CONTAINER_1_HASH);
System.out.println("Wait 5s for DB to get up");
Thread.sleep(5 * 1000);
}
@AfterEach
public void afterEach() {
/* stop containers and remove them */
dockerClient.listContainersCmd()
.withShowAll(true)
.exec()
.forEach(container -> {
try {
dockerClient.stopContainerCmd(container.getId()).exec();
System.out.println("STOP CONTAINER " + Arrays.toString(container.getNames()));
} catch (NotModifiedException e) {
// ignore
}
dockerClient.removeContainerCmd(container.getId()).exec();
System.out.println("DELETE CONTAINER " + Arrays.toString(container.getNames()));
});
}
@Test
public void createTable_succeeds() throws DatabaseConnectionException, TableMalformedException, DataProcessingException {
final TableCreateDto request = TableCreateDto.builder()
.name(TABLE_1_NAME)
.description(TABLE_1_NAME)
.columns(COLUMNS5)
.build();
/* test */
postgresService.createTable(DATABASE_1, request);
}
@Test
public void createTable_noConnection_fails() {
final TableCreateDto request = TableCreateDto.builder()
.name(TABLE_1_NAME)
.description(TABLE_1_NAME)
.columns(COLUMNS5)
.build();
/* test */
assertThrows(DatabaseConnectionException.class, () -> {
postgresService.createTable(DATABASE_2, request);
});
}
@Disabled("cannot test")
@Test
public void createTable_noSql_fails() throws DataProcessingException {
final TableCreateDto request = TableCreateDto.builder()
.name(TABLE_1_NAME)
.description(TABLE_1_NAME)
.columns(COLUMNS5)
.build();
final PostgresService mockService = mock(PostgresService.class);
/* test */
assertThrows(TableMalformedException.class, () -> {
postgresService.createTable(DATABASE_1, request);
});
}
@Disabled("not testable for me")
@Test
public void insertIntoTable_succeeds() throws SQLException, DatabaseConnectionException, DataProcessingException {
final Connection connection = DriverManager.getConnection("jdbc:postgresql://" + CONTAINER_1_INTERNALNAME + ":" + IMAGE_1_PORT + "/" + DATABASE_1_INTERNALNAME, postgresProperties);
connection.prepareStatement(COLUMNS5_CREATE).execute();
final List<Map<String, Object>> data = List.of(Map.of(COLUMN_1_NAME, 1, COLUMN_2_NAME, 2, COLUMN_3_NAME, 3, COLUMN_4_NAME, 4, COLUMN_5_NAME, "Description"));
final List<String> headers = List.of(COLUMN_1_NAME, COLUMN_2_NAME, COLUMN_3_NAME, COLUMN_4_NAME, COLUMN_5_NAME);
postgresService.insertIntoTable(DATABASE_1, TABLE_1, data, headers);
}
@Disabled("not testable for me")
@Test
public void insertIntoTable_noConnection_fails() {
}
@Disabled("not testable for me")
@Test
public void insertIntoTable_noSql_fails() {
}
@Disabled("not testable for me")
@Test
public void getAllRows_succeeds() {
}
@Disabled("not testable for me")
@Test
public void getAllRows_noSql_fails() {
}
@Disabled("not testable for me")
@Test
public void getCreateTableStatement_noSql_fails() {
}
@Disabled("not testable for me")
@Test
public void insertStatement_succeeds() {
}
@Disabled("not testable for me")
@Test
public void getDeleteStatement_noSql_fails() {
}
}
package at.tuwien.service;
import at.tuwien.BaseUnitTest;
import at.tuwien.api.database.table.TableBriefDto;
import at.tuwien.api.database.table.TableCreateDto;
import at.tuwien.api.database.table.TableDto;
import at.tuwien.endpoints.TableEndpoint;
import at.tuwien.entities.database.Database;
import at.tuwien.exception.*;
import at.tuwien.repository.DatabaseRepository;
import at.tuwien.repository.TableRepository;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import java.sql.SQLException;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.when;
@SpringBootTest
@ExtendWith(SpringExtension.class)
public class PostgresUnitTest extends BaseUnitTest {
}
package at.tuwien.config;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.model.HostConfig;
import com.github.dockerjava.api.model.RestartPolicy;
import com.github.dockerjava.core.DefaultDockerClientConfig;
import com.github.dockerjava.core.DockerClientBuilder;
import com.github.dockerjava.core.DockerClientConfig;
import com.github.dockerjava.httpclient5.ApacheDockerHttpClient;
import com.github.dockerjava.transport.DockerHttpClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class DockerConfig {
@Bean
public HostConfig hostConfig() {
return HostConfig.newHostConfig()
.withRestartPolicy(RestartPolicy.alwaysRestart());
}
@Bean
public DockerClient dockerClientConfiguration() {
final DockerClientConfig dockerClientConfig = DefaultDockerClientConfig.createDefaultConfigBuilder()
.withDockerHost("unix:///var/run/docker.sock")
.build();
final DockerHttpClient dockerHttpClient = new ApacheDockerHttpClient.Builder()
.dockerHost(dockerClientConfig.getDockerHost())
.sslConfig(dockerClientConfig.getSSLConfig())
.build();
return DockerClientBuilder.getInstance()
.withDockerHttpClient(dockerHttpClient)
.build();
}
}
...@@ -3,6 +3,7 @@ package at.tuwien.service; ...@@ -3,6 +3,7 @@ package at.tuwien.service;
import at.tuwien.api.database.table.TableCreateDto; import at.tuwien.api.database.table.TableCreateDto;
import at.tuwien.entities.database.table.Table; import at.tuwien.entities.database.table.Table;
import at.tuwien.exception.DataProcessingException;
import java.sql.*; import java.sql.*;
import java.util.List; import java.util.List;
...@@ -15,9 +16,9 @@ public abstract class JdbcConnector { ...@@ -15,9 +16,9 @@ public abstract class JdbcConnector {
return DriverManager.getConnection(url, properties); return DriverManager.getConnection(url, properties);
} }
abstract PreparedStatement getCreateTableStatement(Connection connection, TableCreateDto createDto) throws SQLException; abstract PreparedStatement getCreateTableStatement(Connection connection, TableCreateDto createDto) throws DataProcessingException;
abstract String insertStatement(List<Map<String, Object>> processedData, Table t, List<String> headers); abstract String insertStatement(List<Map<String, Object>> processedData, Table t, List<String> headers);
abstract PreparedStatement getDeleteStatement(Connection connection, Table table) throws SQLException; abstract PreparedStatement getDeleteStatement(Connection connection, Table table) throws DataProcessingException;
} }
...@@ -48,13 +48,13 @@ public class PostgresService extends JdbcConnector { ...@@ -48,13 +48,13 @@ public class PostgresService extends JdbcConnector {
try { try {
connection = open(URL, postgresProperties); connection = open(URL, postgresProperties);
} catch (SQLException e) { } catch (SQLException e) {
log.error("Could not connect to the database container, is it running from Docker container? IT DOES NOT WORK FROM IDE! URL: {} Params: {}", URL, postgresProperties); log.error("Could not connect to the database container, is it running from Docker container? URL: {} Params: {}", URL, postgresProperties);
throw new DatabaseConnectionException("Could not connect to the database container, is it running at: " + URL, e); throw new DatabaseConnectionException("Could not connect to the database container, is it running at: " + URL, e);
} }
return connection; return connection;
} }
public void createTable(Database database, TableCreateDto createDto) throws DatabaseConnectionException, TableMalformedException { public void createTable(Database database, TableCreateDto createDto) throws DatabaseConnectionException, TableMalformedException, DataProcessingException {
try { try {
final PreparedStatement statement = getCreateTableStatement(getConnection(database), createDto); final PreparedStatement statement = getCreateTableStatement(getConnection(database), createDto);
statement.execute(); statement.execute();
...@@ -73,7 +73,7 @@ public class PostgresService extends JdbcConnector { ...@@ -73,7 +73,7 @@ public class PostgresService extends JdbcConnector {
} catch (DatabaseConnectionException e) { } catch (DatabaseConnectionException e) {
log.error("Problem with connecting to the database while selecting from query store: {}", e.getMessage()); log.error("Problem with connecting to the database while selecting from query store: {}", e.getMessage());
throw new DatabaseConnectionException("database connection problem with query store", e); throw new DatabaseConnectionException("database connection problem with query store", e);
} catch (SQLException e) { } catch (SQLException | NullPointerException e) {
log.error("The SQL statement seems to contain invalid syntax: {}", e.getMessage()); log.error("The SQL statement seems to contain invalid syntax: {}", e.getMessage());
throw new DataProcessingException("invalid syntax", e); throw new DataProcessingException("invalid syntax", e);
} }
...@@ -86,7 +86,7 @@ public class PostgresService extends JdbcConnector { ...@@ -86,7 +86,7 @@ public class PostgresService extends JdbcConnector {
* @param t * @param t
* @return * @return
*/ */
public QueryResultDto getAllRows(Database database, Table t) throws DatabaseConnectionException { public QueryResultDto getAllRows(Database database, Table t) throws DatabaseConnectionException, DataProcessingException {
try { try {
Connection connection = getConnection(database); Connection connection = getConnection(database);
PreparedStatement statement = connection.prepareStatement(selectStatement(t)); PreparedStatement statement = connection.prepareStatement(selectStatement(t));
...@@ -103,14 +103,13 @@ public class PostgresService extends JdbcConnector { ...@@ -103,14 +103,13 @@ public class PostgresService extends JdbcConnector {
qr.setResult(res); qr.setResult(res);
return qr; return qr;
} catch (SQLException e) { } catch (SQLException e) {
log.debug(e.getMessage()); log.error("The SQL statement seems to contain invalid syntax: {}", e.getMessage());
log.error("The SQL statement seems to contain invalid syntax"); throw new DataProcessingException("invalid syntax", e);
} }
return null;
} }
@Override @Override
public final PreparedStatement getCreateTableStatement(Connection connection, TableCreateDto createDto) throws SQLException { public final PreparedStatement getCreateTableStatement(Connection connection, TableCreateDto createDto) throws DataProcessingException {
log.debug("create table columns {}", Arrays.toString(createDto.getColumns())); log.debug("create table columns {}", Arrays.toString(createDto.getColumns()));
final StringBuilder queryBuilder = new StringBuilder() final StringBuilder queryBuilder = new StringBuilder()
.append("CREATE TABLE ") .append("CREATE TABLE ")
...@@ -127,25 +126,18 @@ public class PostgresService extends JdbcConnector { ...@@ -127,25 +126,18 @@ public class PostgresService extends JdbcConnector {
queryBuilder.append(");"); queryBuilder.append(");");
final String createQuery = queryBuilder.toString(); final String createQuery = queryBuilder.toString();
log.debug("compiled query as \"{}\"", createQuery); log.debug("compiled query as \"{}\"", createQuery);
try {
return connection.prepareStatement(createQuery); return connection.prepareStatement(createQuery);
} catch (SQLException e) {
log.error("invalid syntax: {}", e.getMessage());
throw new DataProcessingException("invalid syntax", e);
} }
private String selectStatement(Table t) {
log.debug("selecting data from {}", t.getName());
StringBuilder queryBuilder = new StringBuilder()
.append("SELECT ");
for (TableColumn tc : t.getColumns()) {
queryBuilder.append(tc.getInternalName() + ",");
}
queryBuilder.deleteCharAt(queryBuilder.length() - 1);
queryBuilder.append(" FROM " + t.getInternalName());
log.debug(queryBuilder.toString());
return queryBuilder.toString();
} }
/** /**
* FIXME THIS IS REMOVED IN SPRINT 2 * FIXME THIS IS REMOVED IN SPRINT 2
* Very weird ordering of arguments in the processedData for-for loop
* Why not use PostgreSQL COPY statement?
* *
* @param processedData * @param processedData
* @param t * @param t
...@@ -153,22 +145,25 @@ public class PostgresService extends JdbcConnector { ...@@ -153,22 +145,25 @@ public class PostgresService extends JdbcConnector {
*/ */
@Override @Override
public String insertStatement(List<Map<String, Object>> processedData, Table t, List<String> headers) { public String insertStatement(List<Map<String, Object>> processedData, Table t, List<String> headers) {
log.debug("insertStatement data into {}", t.getName()); log.debug("insert table name: {}", t.getInternalName());
StringBuilder queryBuilder = new StringBuilder() StringBuilder queryBuilder = new StringBuilder()
.append("INSERT INTO ") .append("INSERT INTO ")
.append(tableMapper.columnNameToString(t.getInternalName())) .append(tableMapper.columnNameToString(t.getInternalName()))
.append("("); .append("(");
for (String h : headers) { for (String h : headers) {
// FIXME empty columns list in table produces nullpointer exception
queryBuilder.append(t.getColumns().stream().filter(x -> x.getName().equals(h)).findFirst().get().getInternalName() + ","); queryBuilder.append(t.getColumns().stream().filter(x -> x.getName().equals(h)).findFirst().get().getInternalName() + ",");
} }
queryBuilder.deleteCharAt(queryBuilder.length() - 1); queryBuilder.deleteCharAt(queryBuilder.length() - 1);
queryBuilder.append(") VALUES "); queryBuilder.append(") VALUES ");
// FIXME: no rows in processed data produce invalid syntax, but no exception thrown
for (Map<String, Object> m : processedData) { for (Map<String, Object> m : processedData) {
queryBuilder.append("("); queryBuilder.append("(");
// FIXME: no rows in processed data produce invalid syntax, but no exception thrown
for (Map.Entry<String, Object> entry : m.entrySet()) { for (Map.Entry<String, Object> entry : m.entrySet()) {
TableColumn tc = t.getColumns().stream().filter(x -> x.getName().equals(entry.getKey())).findFirst().get(); TableColumn tc = t.getColumns().stream().filter(x -> x.getName().equals(entry.getKey())).findFirst().get();
if (tc.getColumnType().toString().equals("STRING")) { if (tc.getColumnType().toString().equals("STRING") || tc.getColumnType().equals("TEXT")) {
queryBuilder.append("'" + entry.getValue() + "'" + ","); queryBuilder.append("'" + entry.getValue() + "'" + ",");
} else { } else {
queryBuilder.append(entry.getValue() + ","); queryBuilder.append(entry.getValue() + ",");
...@@ -183,7 +178,7 @@ public class PostgresService extends JdbcConnector { ...@@ -183,7 +178,7 @@ public class PostgresService extends JdbcConnector {
return queryBuilder.toString(); return queryBuilder.toString();
} }
public void deleteTable(Table table) throws DatabaseConnectionException, TableMalformedException { public void deleteTable(Table table) throws DatabaseConnectionException, TableMalformedException, DataProcessingException {
try { try {
final PreparedStatement statement = getDeleteStatement(getConnection(table.getDatabase()), table); final PreparedStatement statement = getDeleteStatement(getConnection(table.getDatabase()), table);
statement.execute(); statement.execute();
...@@ -194,12 +189,31 @@ public class PostgresService extends JdbcConnector { ...@@ -194,12 +189,31 @@ public class PostgresService extends JdbcConnector {
} }
@Override @Override
final PreparedStatement getDeleteStatement(Connection connection, Table table) throws SQLException { final PreparedStatement getDeleteStatement(Connection connection, Table table) throws DataProcessingException {
final StringBuilder deleteQuery = new StringBuilder("DROP TABLE ") final StringBuilder deleteQuery = new StringBuilder("DROP TABLE ")
.append(tableMapper.columnNameToString(table.getInternalName())) .append(tableMapper.columnNameToString(table.getInternalName()))
.append(";"); .append(";");
log.debug("compiled delete table statement as {}", deleteQuery.toString()); log.debug("compiled delete table statement as {}", deleteQuery.toString());
try {
return connection.prepareStatement(deleteQuery.toString()); return connection.prepareStatement(deleteQuery.toString());
} catch (SQLException e) {
log.error("invalid syntax: {}", e.getMessage());
throw new DataProcessingException("invalid syntax", e);
}
}
private String selectStatement(Table t) {
log.debug("selecting data from {}", t.getName());
StringBuilder queryBuilder = new StringBuilder()
.append("SELECT ");
for (TableColumn tc : t.getColumns()) {
queryBuilder.append(tc.getInternalName() + ",");
}
queryBuilder.deleteCharAt(queryBuilder.length() - 1);
queryBuilder.append(" FROM " + t.getInternalName());
log.debug(queryBuilder.toString());
return queryBuilder.toString();
} }
/** /**
......
...@@ -69,7 +69,7 @@ public class TableService { ...@@ -69,7 +69,7 @@ public class TableService {
return tables; return tables;
} }
public void delete(Long databaseId, Long tableId) throws TableNotFoundException, DatabaseConnectionException, TableMalformedException { public void delete(Long databaseId, Long tableId) throws TableNotFoundException, DatabaseConnectionException, TableMalformedException, DataProcessingException {
final Table table = findById(databaseId, tableId); final Table table = findById(databaseId, tableId);
postgresService.deleteTable(table); postgresService.deleteTable(table);
tableRepository.deleteById(tableId); tableRepository.deleteById(tableId);
...@@ -104,7 +104,7 @@ public class TableService { ...@@ -104,7 +104,7 @@ public class TableService {
@Transactional @Transactional
public Table create(Long databaseId, TableCreateDto createDto) throws ImageNotSupportedException, public Table create(Long databaseId, TableCreateDto createDto) throws ImageNotSupportedException,
DatabaseConnectionException, TableMalformedException, DatabaseNotFoundException { DatabaseConnectionException, TableMalformedException, DatabaseNotFoundException, DataProcessingException {
final Database database = findDatabase(databaseId); final Database database = findDatabase(databaseId);
/* save in metadata db */ /* save in metadata db */
...@@ -181,7 +181,7 @@ public class TableService { ...@@ -181,7 +181,7 @@ public class TableService {
} }
public QueryResultDto showData(Long databaseId, Long tableId) throws ImageNotSupportedException, public QueryResultDto showData(Long databaseId, Long tableId) throws ImageNotSupportedException,
DatabaseNotFoundException, TableNotFoundException, DatabaseConnectionException { DatabaseNotFoundException, TableNotFoundException, DatabaseConnectionException, DataProcessingException {
QueryResultDto queryResult = postgresService.getAllRows(findDatabase(databaseId), findById(databaseId, tableId)); QueryResultDto queryResult = postgresService.getAllRows(findDatabase(databaseId), findById(databaseId, tableId));
for (Map<String, Object> m : queryResult.getResult()) { for (Map<String, Object> m : queryResult.getResult()) {
for (Map.Entry<String, Object> entry : m.entrySet()) { for (Map.Entry<String, Object> entry : m.entrySet()) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment