Newer
Older
/*
* This file is part of vospace-file-service
* Copyright (C) 2021 Istituto Nazionale di Astrofisica
* SPDX-License-Identifier: GPL-3.0-or-later
*/
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
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$");
}
}