|
21 | 21 | import io.zonky.test.db.liquibase.LiquibaseDatabaseExtension; |
22 | 22 | import io.zonky.test.db.liquibase.LiquibasePropertiesPostProcessor; |
23 | 23 | import io.zonky.test.db.provider.DatabaseProvider; |
24 | | -import io.zonky.test.db.provider.TemplatableDatabaseProvider; |
25 | | -import io.zonky.test.db.provider.common.OptimizingDatabaseProvider; |
26 | | -import io.zonky.test.db.provider.common.PrefetchingDatabaseProvider; |
27 | | -import io.zonky.test.db.provider.common.TemplatingDatabaseProvider; |
28 | 24 | import io.zonky.test.db.provider.mariadb.DockerMariaDBDatabaseProvider; |
29 | 25 | import io.zonky.test.db.provider.mssql.DockerMSSQLDatabaseProvider; |
30 | 26 | import io.zonky.test.db.provider.mysql.DockerMySQLDatabaseProvider; |
|
36 | 32 | import io.zonky.test.db.support.DefaultProviderResolver; |
37 | 33 | import io.zonky.test.db.support.ProviderResolver; |
38 | 34 | import org.springframework.beans.factory.BeanClassLoaderAware; |
39 | | -import org.springframework.beans.factory.BeanFactory; |
40 | | -import org.springframework.beans.factory.BeanFactoryAware; |
41 | 35 | import org.springframework.beans.factory.config.AutowireCapableBeanFactory; |
42 | 36 | import org.springframework.beans.factory.config.BeanDefinition; |
43 | 37 | import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; |
44 | | -import org.springframework.context.EnvironmentAware; |
45 | 38 | import org.springframework.context.annotation.Bean; |
46 | 39 | import org.springframework.context.annotation.Configuration; |
47 | 40 | import org.springframework.context.annotation.Role; |
48 | | -import org.springframework.context.annotation.Scope; |
49 | 41 | import org.springframework.core.env.Environment; |
50 | 42 | import org.springframework.util.ClassUtils; |
51 | 43 |
|
52 | 44 | @Configuration |
53 | | -public class EmbeddedDatabaseAutoConfiguration implements EnvironmentAware, BeanClassLoaderAware, BeanFactoryAware { |
| 45 | +public class EmbeddedDatabaseAutoConfiguration implements BeanClassLoaderAware { |
54 | 46 |
|
55 | | - private Environment environment; |
56 | 47 | private ClassLoader classLoader; |
57 | | - private AutowireCapableBeanFactory beanFactory; |
58 | | - |
59 | | - @Override |
60 | | - public void setEnvironment(Environment environment) { |
61 | | - this.environment = environment; |
62 | | - } |
63 | 48 |
|
64 | 49 | @Override |
65 | 50 | public void setBeanClassLoader(ClassLoader classLoader) { |
66 | 51 | this.classLoader = classLoader; |
67 | 52 | } |
68 | 53 |
|
69 | | - @Override |
70 | | - public void setBeanFactory(BeanFactory beanFactory) { |
71 | | - this.beanFactory = (AutowireCapableBeanFactory) beanFactory; |
72 | | - } |
73 | | - |
74 | 54 | @Bean |
75 | 55 | @Provider(type = "docker", database = "postgres") |
76 | 56 | @ConditionalOnMissingBean(name = "dockerPostgresDatabaseProvider") |
77 | | - public DatabaseProvider dockerPostgresDatabaseProvider() { |
| 57 | + public DatabaseProvider dockerPostgresDatabaseProvider(DatabaseProviderFactory postgresDatabaseProviderFactory) { |
78 | 58 | checkDependency("org.testcontainers", "postgresql", "org.testcontainers.containers.PostgreSQLContainer"); |
79 | 59 | checkDependency("org.postgresql", "postgresql", "org.postgresql.ds.PGSimpleDataSource"); |
80 | | - TemplatableDatabaseProvider provider = beanFactory.createBean(DockerPostgresDatabaseProvider.class); |
81 | | - return optimizingDatabaseProvider(prefetchingDatabaseProvider(templatingDatabaseProvider(provider))); |
| 60 | + return postgresDatabaseProviderFactory.createProvider(DockerPostgresDatabaseProvider.class); |
82 | 61 | } |
83 | 62 |
|
84 | 63 | @Bean |
85 | 64 | @Provider(type = "zonky", database = "postgres") |
86 | 65 | @ConditionalOnMissingBean(name = "zonkyPostgresDatabaseProvider") |
87 | | - public DatabaseProvider zonkyPostgresDatabaseProvider() { |
| 66 | + public DatabaseProvider zonkyPostgresDatabaseProvider(DatabaseProviderFactory postgresDatabaseProviderFactory) { |
88 | 67 | checkDependency("io.zonky.test", "embedded-postgres", "io.zonky.test.db.postgres.embedded.EmbeddedPostgres"); |
89 | 68 | checkDependency("org.postgresql", "postgresql", "org.postgresql.ds.PGSimpleDataSource"); |
90 | | - TemplatableDatabaseProvider provider = beanFactory.createBean(ZonkyPostgresDatabaseProvider.class); |
91 | | - return optimizingDatabaseProvider(prefetchingDatabaseProvider(templatingDatabaseProvider(provider))); |
| 69 | + return postgresDatabaseProviderFactory.createProvider(ZonkyPostgresDatabaseProvider.class); |
92 | 70 | } |
93 | 71 |
|
94 | 72 | @Bean |
95 | 73 | @Provider(type = "opentable", database = "postgres") |
96 | 74 | @ConditionalOnMissingBean(name = "openTablePostgresDatabaseProvider") |
97 | | - public DatabaseProvider openTablePostgresDatabaseProvider() { |
| 75 | + public DatabaseProvider openTablePostgresDatabaseProvider(DatabaseProviderFactory postgresDatabaseProviderFactory) { |
98 | 76 | checkDependency("com.opentable.components", "otj-pg-embedded", "com.opentable.db.postgres.embedded.EmbeddedPostgres"); |
99 | 77 | checkDependency("org.postgresql", "postgresql", "org.postgresql.ds.PGSimpleDataSource"); |
100 | | - TemplatableDatabaseProvider provider = beanFactory.createBean(OpenTablePostgresDatabaseProvider.class); |
101 | | - return optimizingDatabaseProvider(prefetchingDatabaseProvider(templatingDatabaseProvider(provider))); |
| 78 | + return postgresDatabaseProviderFactory.createProvider(OpenTablePostgresDatabaseProvider.class); |
102 | 79 | } |
103 | 80 |
|
104 | 81 | @Bean |
105 | 82 | @Provider(type = "yandex", database = "postgres") |
106 | 83 | @ConditionalOnMissingBean(name = "yandexPostgresDatabaseProvider") |
107 | | - public DatabaseProvider yandexPostgresDatabaseProvider() { |
| 84 | + public DatabaseProvider yandexPostgresDatabaseProvider(DatabaseProviderFactory postgresDatabaseProviderFactory) { |
108 | 85 | checkDependency("ru.yandex.qatools.embed", "postgresql-embedded", "ru.yandex.qatools.embed.postgresql.EmbeddedPostgres"); |
109 | 86 | checkDependency("org.postgresql", "postgresql", "org.postgresql.ds.PGSimpleDataSource"); |
110 | | - TemplatableDatabaseProvider provider = beanFactory.createBean(YandexPostgresDatabaseProvider.class); |
111 | | - return optimizingDatabaseProvider(prefetchingDatabaseProvider(templatingDatabaseProvider(provider))); |
| 87 | + return postgresDatabaseProviderFactory.createProvider(YandexPostgresDatabaseProvider.class); |
112 | 88 | } |
113 | 89 |
|
114 | 90 | @Bean |
115 | 91 | @Provider(type = "docker", database = "mssql") |
116 | 92 | @ConditionalOnMissingBean(name = "dockerMsSqlDatabaseProvider") |
117 | | - public DatabaseProvider dockerMsSqlDatabaseProvider() { |
| 93 | + public DatabaseProvider dockerMsSqlDatabaseProvider(DatabaseProviderFactory msSqlDatabaseProviderFactory) { |
118 | 94 | checkDependency("org.testcontainers", "mssqlserver", "org.testcontainers.containers.MSSQLServerContainer"); |
119 | 95 | checkDependency("com.microsoft.sqlserver", "mssql-jdbc", "com.microsoft.sqlserver.jdbc.SQLServerDataSource"); |
120 | | - DockerMSSQLDatabaseProvider provider = beanFactory.createBean(DockerMSSQLDatabaseProvider.class); |
121 | | - return optimizingDatabaseProvider(prefetchingDatabaseProvider(templatingDatabaseProvider(provider))); |
| 96 | + return msSqlDatabaseProviderFactory.createProvider(DockerMSSQLDatabaseProvider.class); |
122 | 97 | } |
123 | 98 |
|
124 | 99 | @Bean |
125 | 100 | @Provider(type = "docker", database = "mysql") |
126 | 101 | @ConditionalOnMissingBean(name = "dockerMySqlDatabaseProvider") |
127 | | - public DatabaseProvider dockerMySqlDatabaseProvider() { |
| 102 | + public DatabaseProvider dockerMySqlDatabaseProvider(DatabaseProviderFactory mySqlDatabaseProviderFactory) { |
128 | 103 | checkDependency("org.testcontainers", "mysql", "org.testcontainers.containers.MySQLContainer"); |
129 | 104 | checkDependency("mysql", "mysql-connector-java", "com.mysql.cj.jdbc.MysqlDataSource"); |
130 | | - DockerMySQLDatabaseProvider provider = beanFactory.createBean(DockerMySQLDatabaseProvider.class); |
131 | | - return optimizingDatabaseProvider(provider); |
| 105 | + return mySqlDatabaseProviderFactory.createProvider(DockerMySQLDatabaseProvider.class); |
132 | 106 | } |
133 | 107 |
|
134 | 108 | @Bean |
135 | 109 | @Provider(type = "docker", database = "mariadb") |
136 | 110 | @ConditionalOnMissingBean(name = "dockerMariaDbDatabaseProvider") |
137 | | - public DatabaseProvider dockerMariaDbDatabaseProvider() { |
| 111 | + public DatabaseProvider dockerMariaDbDatabaseProvider(DatabaseProviderFactory mariaDbDatabaseProviderFactory) { |
138 | 112 | checkDependency("org.testcontainers", "mariadb", "org.testcontainers.containers.MariaDBContainer"); |
139 | 113 | checkDependency("org.mariadb.jdbc", "mariadb-java-client", "org.mariadb.jdbc.MariaDbDataSource"); |
140 | | - DockerMariaDBDatabaseProvider provider = beanFactory.createBean(DockerMariaDBDatabaseProvider.class); |
141 | | - return optimizingDatabaseProvider(provider); |
| 114 | + return mariaDbDatabaseProviderFactory.createProvider(DockerMariaDBDatabaseProvider.class); |
| 115 | + } |
| 116 | + |
| 117 | + @Bean |
| 118 | + @Role(BeanDefinition.ROLE_INFRASTRUCTURE) |
| 119 | + @ConditionalOnMissingBean(name = "postgresDatabaseProviderFactory") |
| 120 | + public DatabaseProviderFactory postgresDatabaseProviderFactory(DatabaseProviderFactory defaultDatabaseProviderFactory) { |
| 121 | + return defaultDatabaseProviderFactory.customizeProvider((builder, provider) -> |
| 122 | + builder.optimizingProvider( |
| 123 | + builder.prefetchingProvider( |
| 124 | + builder.templatingProvider(provider)))); |
| 125 | + } |
| 126 | + |
| 127 | + @Bean |
| 128 | + @Role(BeanDefinition.ROLE_INFRASTRUCTURE) |
| 129 | + @ConditionalOnMissingBean(name = "msSqlDatabaseProviderFactory") |
| 130 | + public DatabaseProviderFactory msSqlDatabaseProviderFactory(DatabaseProviderFactory defaultDatabaseProviderFactory) { |
| 131 | + return defaultDatabaseProviderFactory.customizeProvider((builder, provider) -> |
| 132 | + builder.optimizingProvider( |
| 133 | + builder.prefetchingProvider( |
| 134 | + builder.templatingProvider(provider)))); |
142 | 135 | } |
143 | 136 |
|
144 | 137 | @Bean |
145 | | - @Scope("prototype") |
146 | 138 | @Role(BeanDefinition.ROLE_INFRASTRUCTURE) |
147 | | - @ConditionalOnMissingBean(name = "optimizingDatabaseProvider") |
148 | | - public OptimizingDatabaseProvider optimizingDatabaseProvider(DatabaseProvider provider) { |
149 | | - return new OptimizingDatabaseProvider(provider); |
| 139 | + @ConditionalOnMissingBean(name = "mySqlDatabaseProviderFactory") |
| 140 | + public DatabaseProviderFactory mySqlDatabaseProviderFactory(DatabaseProviderFactory defaultDatabaseProviderFactory) { |
| 141 | + return defaultDatabaseProviderFactory.customizeProvider((builder, provider) -> |
| 142 | + builder.optimizingProvider(provider)); |
150 | 143 | } |
151 | 144 |
|
152 | | - // TODO: consider using a factory bean instead (also consider using pipeline factories aimed for specific provider types) |
153 | 145 | @Bean |
154 | | - @Scope("prototype") |
155 | 146 | @Role(BeanDefinition.ROLE_INFRASTRUCTURE) |
156 | | - @ConditionalOnMissingBean(name = "prefetchingDatabaseProvider") |
157 | | - public PrefetchingDatabaseProvider prefetchingDatabaseProvider(DatabaseProvider provider) { |
158 | | - return new PrefetchingDatabaseProvider(provider, environment); |
| 147 | + @ConditionalOnMissingBean(name = "mariaDbDatabaseProviderFactory") |
| 148 | + public DatabaseProviderFactory mariaDbDatabaseProviderFactory(DatabaseProviderFactory defaultDatabaseProviderFactory) { |
| 149 | + return defaultDatabaseProviderFactory.customizeProvider((builder, provider) -> |
| 150 | + builder.optimizingProvider(provider)); |
159 | 151 | } |
160 | 152 |
|
161 | 153 | @Bean |
162 | | - @Scope("prototype") |
163 | 154 | @Role(BeanDefinition.ROLE_INFRASTRUCTURE) |
164 | | - @ConditionalOnMissingBean(name = "templatingDatabaseProvider") |
165 | | - public TemplatingDatabaseProvider templatingDatabaseProvider(TemplatableDatabaseProvider provider) { |
166 | | - return new TemplatingDatabaseProvider(provider); |
| 155 | + @ConditionalOnMissingBean(name = "defaultDatabaseProviderFactory") |
| 156 | + public DatabaseProviderFactory defaultDatabaseProviderFactory(AutowireCapableBeanFactory beanFactory, Environment environment) { |
| 157 | + String threadNamePrefix = environment.getProperty("zonky.test.database.prefetching.thread-name-prefix", "prefetching-"); |
| 158 | + int concurrency = environment.getProperty("zonky.test.database.prefetching.concurrency", int.class, 3); |
| 159 | + int pipelineCacheSize = environment.getProperty("zonky.test.database.prefetching.pipeline-cache-size", int.class, 5); |
| 160 | + int maxPreparedTemplates = environment.getProperty("zonky.test.database.prefetching.max-prepared-templates", int.class, 10); |
| 161 | + int maxPreparedDatabases = (maxPreparedTemplates * 2/3 * 2) + pipelineCacheSize; |
| 162 | + |
| 163 | + return new DatabaseProviderFactory(beanFactory) |
| 164 | + .customizeTemplating(builder -> builder |
| 165 | + .withMaxTemplateCount(maxPreparedTemplates)) |
| 166 | + .customizePrefetching(builder -> builder |
| 167 | + .withThreadNamePrefix(threadNamePrefix) |
| 168 | + .withConcurrency(concurrency) |
| 169 | + .withPipelineMaxCacheSize(pipelineCacheSize) |
| 170 | + .withMaxPreparedDatabases(maxPreparedDatabases)); |
167 | 171 | } |
168 | 172 |
|
169 | 173 | @Bean |
|
0 commit comments