001package io.ebean.test.config.platform; 002 003import io.ebean.config.DatabaseConfig; 004import io.ebean.docker.container.ContainerFactory; 005import org.slf4j.Logger; 006import org.slf4j.LoggerFactory; 007 008import java.util.HashMap; 009import java.util.Map; 010import java.util.Properties; 011 012import static java.util.concurrent.CompletableFuture.allOf; 013import static java.util.concurrent.CompletableFuture.runAsync; 014 015public class PlatformAutoConfig { 016 017 private static final Logger log = LoggerFactory.getLogger("io.ebean.test"); 018 019 /** 020 * Known platforms we can setup locally or via docker container. 021 */ 022 private static final Map<String, PlatformSetup> KNOWN_PLATFORMS = new HashMap<>(); 023 024 static { 025 KNOWN_PLATFORMS.put("h2", new H2Setup()); 026 KNOWN_PLATFORMS.put("sqlite", new SqliteSetup()); 027 KNOWN_PLATFORMS.put("postgres", new PostgresSetup()); 028 KNOWN_PLATFORMS.put("postgis", new PostgisSetup()); 029 KNOWN_PLATFORMS.put("nuodb", new NuoDBSetup()); 030 KNOWN_PLATFORMS.put("mysql", new MySqlSetup()); 031 KNOWN_PLATFORMS.put("mariadb", new MariaDBSetup()); 032 KNOWN_PLATFORMS.put("sqlserver", new SqlServerSetup()); 033 KNOWN_PLATFORMS.put("oracle", new OracleSetup()); 034 KNOWN_PLATFORMS.put("clickhouse", new ClickHouseSetup()); 035 KNOWN_PLATFORMS.put("cockroach", new CockroachSetup()); 036 KNOWN_PLATFORMS.put("hana", new HanaSetup()); 037 KNOWN_PLATFORMS.put("db2", new Db2Setup()); 038 KNOWN_PLATFORMS.put("yugabyte", new YugabyteSetup()); 039 } 040 041 private final DatabaseConfig config; 042 private final Properties properties; 043 private String db; 044 private String platform; 045 private PlatformSetup platformSetup; 046 private String databaseName; 047 048 public PlatformAutoConfig(String db, DatabaseConfig config) { 049 this.db = db; 050 this.config = config; 051 this.properties = config.getProperties(); 052 } 053 054 /** 055 * Configure the DataSource for the extra database. 056 */ 057 public void configExtraDataSource() { 058 determineTestPlatform(); 059 if (isKnownPlatform()) { 060 databaseName = config.getName(); 061 db = config.getName(); 062 063 Config config = new Config(db, platform, databaseName, this.config); 064 platformSetup.setupExtraDbDataSource(config); 065 log.debug("configured dataSource for extraDb name:{} url:{}", db, this.config.getDataSourceConfig().getUrl()); 066 } 067 } 068 069 /** 070 * Run setting up for testing. 071 */ 072 public void run() { 073 determineTestPlatform(); 074 if (isKnownPlatform()) { 075 readDbName(); 076 setupForTesting(); 077 } 078 } 079 080 private void setupForTesting() { 081 // start containers in parallel 082 RedisSetup.run(properties); 083 allOf(runAsync(this::setupElasticSearch), runAsync(this::setupDatabase)).join(); 084 } 085 086 private void setupElasticSearch() { 087 new ElasticSearchSetup(properties).run(); 088 } 089 090 private void setupDatabase() { 091 Config config = new Config(db, platform, databaseName, this.config); 092 Properties dockerProperties = platformSetup.setup(config); 093 if (!dockerProperties.isEmpty()) { 094 if (isDebug()) { 095 log.info("Docker properties: {}", dockerProperties); 096 } else { 097 log.debug("Docker properties: {}", dockerProperties); 098 } 099 // start the docker container with appropriate configuration 100 new ContainerFactory(dockerProperties, config.getDockerPlatform()).startContainers(); 101 } 102 } 103 104 private boolean isDebug() { 105 String val = properties.getProperty("ebean.test.debug"); 106 return (val != null && val.equalsIgnoreCase("true")); 107 } 108 109 private void readDbName() { 110 databaseName = properties.getProperty("ebean.test.dbName"); 111 if (databaseName == null) { 112 if (inMemoryDb()) { 113 databaseName = "test_db"; 114 } else { 115 throw new IllegalStateException("ebean.test.dbName is not set but required for testing configuration with platform " + platform); 116 } 117 } 118 } 119 120 private boolean inMemoryDb() { 121 return platformSetup.isLocal(); 122 } 123 124 /** 125 * Return true if we match a known platform and know how to set it up for testing (via docker usually). 126 */ 127 private boolean isKnownPlatform() { 128 if (platform == null) { 129 return false; 130 } 131 this.platformSetup = KNOWN_PLATFORMS.get(platform); 132 if (platformSetup == null) { 133 log.warn("unknown platform {} - skipping platform setup", platform); 134 } 135 return platformSetup != null; 136 } 137 138 /** 139 * Determine the platform we are going to use to run testing. 140 */ 141 private void determineTestPlatform() { 142 String testPlatform = properties.getProperty("ebean.test.platform"); 143 if (testPlatform != null && !testPlatform.isEmpty()) { 144 if (db == null) { 145 platform = testPlatform.trim(); 146 db = "db"; 147 } else { 148 // using command line system property to test alternate platform 149 // and we expect db to match a platform name 150 platform = db; 151 } 152 } 153 } 154}