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(PlatformAutoConfig.class); 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 } 038 039 private final DatabaseConfig config; 040 041 private final Properties properties; 042 043 private String db; 044 045 private String platform; 046 047 private PlatformSetup platformSetup; 048 049 private String databaseName; 050 051 public PlatformAutoConfig(String db, DatabaseConfig config) { 052 this.db = db; 053 this.config = config; 054 this.properties = config.getProperties(); 055 } 056 057 /** 058 * Configure the DataSource for the extra database. 059 */ 060 public void configExtraDataSource() { 061 determineTestPlatform(); 062 if (isKnownPlatform()) { 063 databaseName = config.getName(); 064 db = config.getName(); 065 066 Config config = new Config(db, platform, databaseName, this.config); 067 platformSetup.setupExtraDbDataSource(config); 068 log.debug("configured dataSource for extraDb name:{} url:{}", db, this.config.getDataSourceConfig().getUrl()); 069 } 070 } 071 072 /** 073 * Run setting up for testing. 074 */ 075 public void run() { 076 determineTestPlatform(); 077 if (isKnownPlatform()) { 078 readDbName(); 079 setupForTesting(); 080 } 081 } 082 083 private void setupForTesting() { 084 // start containers in parallel 085 RedisSetup.run(properties); 086 allOf(runAsync(this::setupElasticSearch), runAsync(this::setupDatabase)).join(); 087 } 088 089 private void setupElasticSearch() { 090 new ElasticSearchSetup(properties).run(); 091 } 092 093 private void setupDatabase() { 094 Config config = new Config(db, platform, databaseName, this.config); 095 Properties dockerProperties = platformSetup.setup(config); 096 if (!dockerProperties.isEmpty()) { 097 if (isDebug()) { 098 log.info("Docker properties: {}", dockerProperties); 099 } else { 100 log.debug("Docker properties: {}", dockerProperties); 101 } 102 // start the docker container with appropriate configuration 103 new ContainerFactory(dockerProperties, config.getDockerPlatform()).startContainers(); 104 } 105 } 106 107 private boolean isDebug() { 108 String val = properties.getProperty("ebean.test.debug"); 109 return (val != null && val.equalsIgnoreCase("true")); 110 } 111 112 private void readDbName() { 113 databaseName = properties.getProperty("ebean.test.dbName"); 114 if (databaseName == null) { 115 if (inMemoryDb()) { 116 databaseName = "test_db"; 117 } else { 118 throw new IllegalStateException("ebean.test.dbName is not set but required for testing configuration with platform " + platform); 119 } 120 } 121 } 122 123 private boolean inMemoryDb() { 124 return platformSetup.isLocal(); 125 } 126 127 /** 128 * Return true if we match a known platform and know how to set it up for testing (via docker usually). 129 */ 130 private boolean isKnownPlatform() { 131 if (platform == null) { 132 return false; 133 } 134 this.platformSetup = KNOWN_PLATFORMS.get(platform); 135 if (platformSetup == null) { 136 log.warn("unknown platform {} - skipping platform setup", platform); 137 } 138 return platformSetup != null; 139 } 140 141 /** 142 * Determine the platform we are going to use to run testing. 143 */ 144 private void determineTestPlatform() { 145 String testPlatform = properties.getProperty("ebean.test.platform"); 146 if (testPlatform != null && !testPlatform.isEmpty()) { 147 if (db == null) { 148 platform = testPlatform.trim(); 149 db = "db"; 150 } else { 151 // using command line system property to test alternate platform 152 // and we expect db to match a platform name 153 platform = db; 154 } 155 } 156 } 157}