Loading .gitlab-ci.yml +8 −0 Original line number Diff line number Diff line Loading @@ -2,11 +2,19 @@ stages: - test - dockerize variables: # to avoid "fatal: git fetch-pack: expected shallow list" GIT_STRATEGY: clone test: stage: test tags: - docker image: "git.ia2.inaf.it:5050/vospace/vospace-oats/vospace-test-env" variables: FILE_CATALOG_REPO_URL: "https://gitlab-ci-token:${CI_JOB_TOKEN}@www.ict.inaf.it/gitlab/vospace/vospace-file-catalog.git" script: - git clone ${FILE_CATALOG_REPO_URL} - mvn clean test - awk -F"," '{ instructions += $4 + $5; covered += $5 } END { print "coverage=" 100*covered/instructions }' target/site/jacoco/jacoco.csv coverage: '/coverage=\d+\.\d+/' Loading pom.xml +65 −1 Original line number Diff line number Diff line Loading @@ -15,8 +15,10 @@ <description>VOSpace File service</description> <properties> <java.version>14</java.version> <finalName>${project.artifactId}-${project.version}</finalName> <!-- File catalog repository directory --> <init_database_scripts_path>../../../vospace-file-catalog</init_database_scripts_path> <zonky.postgres-binaries.version>12.5.0</zonky.postgres-binaries.version> </properties> <dependencies> Loading Loading @@ -57,7 +59,50 @@ <artifactId>rap-client</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <!-- Embedded PostgreSQL: --> <dependency> <groupId>com.opentable.components</groupId> <artifactId>otj-pg-embedded</artifactId> <version>0.13.3</version> <scope>test</scope> </dependency> </dependencies> <profiles> <profile> <id>platform-linux</id> <activation> <os> <family>unix</family> </os> </activation> <dependencies> <dependency> <groupId>io.zonky.test.postgres</groupId> <artifactId>embedded-postgres-binaries-linux-amd64</artifactId> <version>${zonky.postgres-binaries.version}</version> <scope>test</scope> </dependency> </dependencies> </profile> <profile> <id>platform-windows</id> <activation> <os> <family>windows</family> </os> </activation> <dependencies> <dependency> <groupId>io.zonky.test.postgres</groupId> <artifactId>embedded-postgres-binaries-windows-amd64</artifactId> <version>${zonky.postgres-binaries.version}</version> <scope>test</scope> </dependency> </dependencies> </profile> </profiles> <repositories> <repository> Loading @@ -69,6 +114,25 @@ <build> <finalName>${finalName}</finalName> <testResources> <testResource> <directory>src/test/resources</directory> <filtering>true</filtering> <includes> <include>test.properties</include> </includes> </testResource> <testResource> <directory>src/test/resources</directory> <filtering>false</filtering> <includes> <include>**/*</include> </includes> <excludes> <exclude>test.properties</exclude> </excludes> </testResource> </testResources> <plugins> <plugin> <artifactId>maven-surefire-plugin</artifactId> Loading src/test/java/it/inaf/ia2/transfer/persistence/DataSourceConfig.java 0 → 100644 +123 −0 Original line number Diff line number Diff line package it.inaf.ia2.transfer.persistence; import com.opentable.db.postgres.embedded.EmbeddedPostgres; import com.opentable.db.postgres.embedded.PgBinaryResolver; import com.opentable.db.postgres.embedded.UncompressBundleDirectoryResolver; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.sql.Connection; import java.util.Arrays; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.sql.DataSource; import static org.junit.jupiter.api.Assertions.assertTrue; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Scope; import org.springframework.core.io.ByteArrayResource; import org.springframework.core.io.ClassPathResource; import org.springframework.jdbc.datasource.init.ScriptUtils; /** * Generates a DataSource that can be used for testing DAO classes. It loads an * embedded Postgres database and fills it using the data from * vospace-transfer-service repository (folder must exists; it location can be * configured using the init_database_scripts_path in test.properties). */ @TestConfiguration public class DataSourceConfig { @Value("${init_database_scripts_path}") private String scriptPath; /** * Using the prototype scope we are generating a different database in each * test. */ @Bean @Scope("prototype") @Primary public DataSource dataSource() throws Exception { DataSource embeddedPostgresDS = EmbeddedPostgres.builder() .setPgDirectoryResolver(new UncompressBundleDirectoryResolver(new CustomPostgresBinaryResolver())) .start().getPostgresDatabase(); initDatabase(embeddedPostgresDS); return embeddedPostgresDS; } private class CustomPostgresBinaryResolver implements PgBinaryResolver { /** * Loads specific embedded Postgres version. */ @Override public InputStream getPgBinary(String system, String architecture) throws IOException { ClassPathResource resource = new ClassPathResource(String.format("postgres-%s-%s.txz", system.toLowerCase(), architecture)); return resource.getInputStream(); } } /** * Loads SQL scripts for database initialization from * vospace-transfer-service repo directory. */ private void initDatabase(DataSource dataSource) throws Exception { try ( Connection conn = dataSource.getConnection()) { File currentDir = new File(DataSourceConfig.class.getClassLoader().getResource(".").getFile()); File scriptDir = currentDir.toPath().resolve(scriptPath).toFile().getCanonicalFile(); assertTrue(scriptDir.exists(), "DAO tests require " + scriptDir.getAbsolutePath() + " to exists.\n" + "Please clone the repository from https://www.ict.inaf.it/gitlab/vospace/vospace-file-catalog.git"); File[] scripts = scriptDir.listFiles(f -> f.getName().endsWith(".sql")); Arrays.sort(scripts); // sort alphabetically for (File script : scripts) { ByteArrayResource scriptResource = replaceDollarQuoting(script.toPath()); ScriptUtils.executeSqlScript(conn, scriptResource); } ScriptUtils.executeSqlScript(conn, new ClassPathResource("test-data.sql")); } } /** * It seems that dollar quoting (used in UDF) is broken in JDBC. Replacing * it with single quotes solves the problem. We replace the quoting here * instead of inside the original files because dollar quoting provides a * better visibility. */ private ByteArrayResource replaceDollarQuoting(Path sqlScriptPath) throws Exception { String scriptContent = Files.readString(sqlScriptPath); if (scriptContent.contains("$func$")) { String func = extractFunctionDefinition(scriptContent); String originalFunction = "$func$" + func + "$func$"; String newFunction = "'" + func.replaceAll("'", "''") + "'"; scriptContent = scriptContent.replace(originalFunction, newFunction); } return new ByteArrayResource(scriptContent.getBytes()); } private String extractFunctionDefinition(String scriptContent) { Pattern pattern = Pattern.compile("\\$func\\$(.*?)\\$func\\$", Pattern.DOTALL); Matcher matcher = pattern.matcher(scriptContent); if (matcher.find()) { return matcher.group(1); } throw new IllegalArgumentException(scriptContent + " doesn't contain $func$"); } } src/test/resources/test-data.sql 0 → 100644 +9 −0 Original line number Diff line number Diff line DELETE FROM node; ALTER SEQUENCE node_node_id_seq RESTART WITH 1; INSERT INTO node (parent_path, parent_relative_path, name, type, owner_id, creator_id) VALUES (NULL, NULL, '', 'container', '0', '0'); INSERT INTO node (parent_path, parent_relative_path, name, type, owner_id, creator_id, group_read, group_write) VALUES ('', NULL, 'test1', 'container', 'user1', 'user1', '{"group1","group2"}','{"group2"}'); -- /test1 INSERT INTO node (parent_path, parent_relative_path, name, type, owner_id, creator_id, group_read, group_write) VALUES ('2', NULL, '.tmp-123.txt', 'structured', 'user1', 'user1', '{"group1","group2"}','{"group2"}'); -- /test1/.tmp-123.txt INSERT INTO node (parent_path, parent_relative_path, name, type, owner_id, creator_id, group_read, group_write) VALUES ('2', NULL, 'file1.txt', 'data', 'user1', 'user1', '{"group1","group2"}','{"group2"}'); -- /test1/file1.txt INSERT INTO node (parent_path, parent_relative_path, name, type, owner_id, creator_id, group_read, group_write) VALUES ('2', NULL, 'file2.txt', 'data', 'user1', 'user1', '{"group1","group2"}','{"group2"}'); -- /test1/file2.txt src/test/resources/test.properties 0 → 100644 +2 −0 Original line number Diff line number Diff line # File catalog repository directory (filled by pom.xml, overridable passing environment variable) init_database_scripts_path=@init_database_scripts_path@ Loading
.gitlab-ci.yml +8 −0 Original line number Diff line number Diff line Loading @@ -2,11 +2,19 @@ stages: - test - dockerize variables: # to avoid "fatal: git fetch-pack: expected shallow list" GIT_STRATEGY: clone test: stage: test tags: - docker image: "git.ia2.inaf.it:5050/vospace/vospace-oats/vospace-test-env" variables: FILE_CATALOG_REPO_URL: "https://gitlab-ci-token:${CI_JOB_TOKEN}@www.ict.inaf.it/gitlab/vospace/vospace-file-catalog.git" script: - git clone ${FILE_CATALOG_REPO_URL} - mvn clean test - awk -F"," '{ instructions += $4 + $5; covered += $5 } END { print "coverage=" 100*covered/instructions }' target/site/jacoco/jacoco.csv coverage: '/coverage=\d+\.\d+/' Loading
pom.xml +65 −1 Original line number Diff line number Diff line Loading @@ -15,8 +15,10 @@ <description>VOSpace File service</description> <properties> <java.version>14</java.version> <finalName>${project.artifactId}-${project.version}</finalName> <!-- File catalog repository directory --> <init_database_scripts_path>../../../vospace-file-catalog</init_database_scripts_path> <zonky.postgres-binaries.version>12.5.0</zonky.postgres-binaries.version> </properties> <dependencies> Loading Loading @@ -57,7 +59,50 @@ <artifactId>rap-client</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <!-- Embedded PostgreSQL: --> <dependency> <groupId>com.opentable.components</groupId> <artifactId>otj-pg-embedded</artifactId> <version>0.13.3</version> <scope>test</scope> </dependency> </dependencies> <profiles> <profile> <id>platform-linux</id> <activation> <os> <family>unix</family> </os> </activation> <dependencies> <dependency> <groupId>io.zonky.test.postgres</groupId> <artifactId>embedded-postgres-binaries-linux-amd64</artifactId> <version>${zonky.postgres-binaries.version}</version> <scope>test</scope> </dependency> </dependencies> </profile> <profile> <id>platform-windows</id> <activation> <os> <family>windows</family> </os> </activation> <dependencies> <dependency> <groupId>io.zonky.test.postgres</groupId> <artifactId>embedded-postgres-binaries-windows-amd64</artifactId> <version>${zonky.postgres-binaries.version}</version> <scope>test</scope> </dependency> </dependencies> </profile> </profiles> <repositories> <repository> Loading @@ -69,6 +114,25 @@ <build> <finalName>${finalName}</finalName> <testResources> <testResource> <directory>src/test/resources</directory> <filtering>true</filtering> <includes> <include>test.properties</include> </includes> </testResource> <testResource> <directory>src/test/resources</directory> <filtering>false</filtering> <includes> <include>**/*</include> </includes> <excludes> <exclude>test.properties</exclude> </excludes> </testResource> </testResources> <plugins> <plugin> <artifactId>maven-surefire-plugin</artifactId> Loading
src/test/java/it/inaf/ia2/transfer/persistence/DataSourceConfig.java 0 → 100644 +123 −0 Original line number Diff line number Diff line package it.inaf.ia2.transfer.persistence; import com.opentable.db.postgres.embedded.EmbeddedPostgres; import com.opentable.db.postgres.embedded.PgBinaryResolver; import com.opentable.db.postgres.embedded.UncompressBundleDirectoryResolver; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.sql.Connection; import java.util.Arrays; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.sql.DataSource; import static org.junit.jupiter.api.Assertions.assertTrue; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Scope; import org.springframework.core.io.ByteArrayResource; import org.springframework.core.io.ClassPathResource; import org.springframework.jdbc.datasource.init.ScriptUtils; /** * Generates a DataSource that can be used for testing DAO classes. It loads an * embedded Postgres database and fills it using the data from * vospace-transfer-service repository (folder must exists; it location can be * configured using the init_database_scripts_path in test.properties). */ @TestConfiguration public class DataSourceConfig { @Value("${init_database_scripts_path}") private String scriptPath; /** * Using the prototype scope we are generating a different database in each * test. */ @Bean @Scope("prototype") @Primary public DataSource dataSource() throws Exception { DataSource embeddedPostgresDS = EmbeddedPostgres.builder() .setPgDirectoryResolver(new UncompressBundleDirectoryResolver(new CustomPostgresBinaryResolver())) .start().getPostgresDatabase(); initDatabase(embeddedPostgresDS); return embeddedPostgresDS; } private class CustomPostgresBinaryResolver implements PgBinaryResolver { /** * Loads specific embedded Postgres version. */ @Override public InputStream getPgBinary(String system, String architecture) throws IOException { ClassPathResource resource = new ClassPathResource(String.format("postgres-%s-%s.txz", system.toLowerCase(), architecture)); return resource.getInputStream(); } } /** * Loads SQL scripts for database initialization from * vospace-transfer-service repo directory. */ private void initDatabase(DataSource dataSource) throws Exception { try ( Connection conn = dataSource.getConnection()) { File currentDir = new File(DataSourceConfig.class.getClassLoader().getResource(".").getFile()); File scriptDir = currentDir.toPath().resolve(scriptPath).toFile().getCanonicalFile(); assertTrue(scriptDir.exists(), "DAO tests require " + scriptDir.getAbsolutePath() + " to exists.\n" + "Please clone the repository from https://www.ict.inaf.it/gitlab/vospace/vospace-file-catalog.git"); File[] scripts = scriptDir.listFiles(f -> f.getName().endsWith(".sql")); Arrays.sort(scripts); // sort alphabetically for (File script : scripts) { ByteArrayResource scriptResource = replaceDollarQuoting(script.toPath()); ScriptUtils.executeSqlScript(conn, scriptResource); } ScriptUtils.executeSqlScript(conn, new ClassPathResource("test-data.sql")); } } /** * It seems that dollar quoting (used in UDF) is broken in JDBC. Replacing * it with single quotes solves the problem. We replace the quoting here * instead of inside the original files because dollar quoting provides a * better visibility. */ private ByteArrayResource replaceDollarQuoting(Path sqlScriptPath) throws Exception { String scriptContent = Files.readString(sqlScriptPath); if (scriptContent.contains("$func$")) { String func = extractFunctionDefinition(scriptContent); String originalFunction = "$func$" + func + "$func$"; String newFunction = "'" + func.replaceAll("'", "''") + "'"; scriptContent = scriptContent.replace(originalFunction, newFunction); } return new ByteArrayResource(scriptContent.getBytes()); } private String extractFunctionDefinition(String scriptContent) { Pattern pattern = Pattern.compile("\\$func\\$(.*?)\\$func\\$", Pattern.DOTALL); Matcher matcher = pattern.matcher(scriptContent); if (matcher.find()) { return matcher.group(1); } throw new IllegalArgumentException(scriptContent + " doesn't contain $func$"); } }
src/test/resources/test-data.sql 0 → 100644 +9 −0 Original line number Diff line number Diff line DELETE FROM node; ALTER SEQUENCE node_node_id_seq RESTART WITH 1; INSERT INTO node (parent_path, parent_relative_path, name, type, owner_id, creator_id) VALUES (NULL, NULL, '', 'container', '0', '0'); INSERT INTO node (parent_path, parent_relative_path, name, type, owner_id, creator_id, group_read, group_write) VALUES ('', NULL, 'test1', 'container', 'user1', 'user1', '{"group1","group2"}','{"group2"}'); -- /test1 INSERT INTO node (parent_path, parent_relative_path, name, type, owner_id, creator_id, group_read, group_write) VALUES ('2', NULL, '.tmp-123.txt', 'structured', 'user1', 'user1', '{"group1","group2"}','{"group2"}'); -- /test1/.tmp-123.txt INSERT INTO node (parent_path, parent_relative_path, name, type, owner_id, creator_id, group_read, group_write) VALUES ('2', NULL, 'file1.txt', 'data', 'user1', 'user1', '{"group1","group2"}','{"group2"}'); -- /test1/file1.txt INSERT INTO node (parent_path, parent_relative_path, name, type, owner_id, creator_id, group_read, group_write) VALUES ('2', NULL, 'file2.txt', 'data', 'user1', 'user1', '{"group1","group2"}','{"group2"}'); -- /test1/file2.txt
src/test/resources/test.properties 0 → 100644 +2 −0 Original line number Diff line number Diff line # File catalog repository directory (filled by pom.xml, overridable passing environment variable) init_database_scripts_path=@init_database_scripts_path@