001/* 002 * (C) Copyright 2006-2015 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Florent Guillaume 018 */ 019package org.nuxeo.ecm.core.test; 020 021import static org.junit.Assert.assertNotNull; 022 023import java.net.URL; 024import java.sql.SQLException; 025import java.util.Arrays; 026import java.util.Collections; 027import java.util.List; 028 029import org.apache.commons.logging.Log; 030import org.apache.commons.logging.LogFactory; 031import org.nuxeo.ecm.core.api.NuxeoException; 032import org.nuxeo.ecm.core.storage.dbs.DBSHelper; 033import org.nuxeo.ecm.core.storage.sql.DatabaseDB2; 034import org.nuxeo.ecm.core.storage.sql.DatabaseDerby; 035import org.nuxeo.ecm.core.storage.sql.DatabaseH2; 036import org.nuxeo.ecm.core.storage.sql.DatabaseHelper; 037import org.nuxeo.ecm.core.storage.sql.DatabaseMySQL; 038import org.nuxeo.ecm.core.storage.sql.DatabaseOracle; 039import org.nuxeo.ecm.core.storage.sql.DatabasePostgreSQL; 040import org.nuxeo.ecm.core.storage.sql.DatabaseSQLServer; 041import org.nuxeo.runtime.api.Framework; 042import org.nuxeo.runtime.mongodb.MongoDBConnectionHelper; 043import org.nuxeo.runtime.test.runner.FeaturesRunner; 044import org.nuxeo.runtime.test.runner.RuntimeFeature; 045import org.nuxeo.runtime.test.runner.RuntimeHarness; 046import org.osgi.framework.Bundle; 047 048import com.mongodb.MongoClient; 049import com.mongodb.client.MongoDatabase; 050 051/** 052 * Description of the specific capabilities of a repository for tests, and helper methods. 053 * 054 * @since 7.3 055 */ 056public class StorageConfiguration { 057 058 private static final Log log = LogFactory.getLog(StorageConfiguration.class); 059 060 public static final String CORE_PROPERTY = "nuxeo.test.core"; 061 062 public static final String CORE_VCS = "vcs"; 063 064 public static final String CORE_MEM = "mem"; 065 066 public static final String CORE_MONGODB = "mongodb"; 067 068 public static final String CORE_MARKLOGIC = "marklogic"; 069 070 public static final String DEFAULT_CORE = CORE_VCS; 071 072 private static final String MONGODB_SERVER_PROPERTY = "nuxeo.test.mongodb.server"; 073 074 private static final String MONGODB_DBNAME_PROPERTY = "nuxeo.test.mongodb.dbname"; 075 076 public static final String DEFAULT_MONGODB_SERVER = "localhost:27017"; 077 078 public static final String DEFAULT_MONGODB_DBNAME = "unittests"; 079 080 private static final String CHANGE_TOKEN_ENABLED_PROPERTY = "nuxeo.test.changetoken.enabled"; 081 082 private static final String CHANGE_TOKEN_ENABLED_DEFAULT = "true"; 083 084 private String coreType; 085 086 private boolean isVCS; 087 088 private boolean isDBS; 089 090 private DatabaseHelper databaseHelper; 091 092 private DBSHelper dbsHelper; 093 094 final CoreFeature feature; 095 096 private boolean changeTokenEnabled; 097 098 public StorageConfiguration(CoreFeature feature) { 099 coreType = defaultSystemProperty(CORE_PROPERTY, DEFAULT_CORE); 100 this.feature = feature; 101 } 102 103 public static String defaultSystemProperty(String name, String def) { 104 String value = System.getProperty(name); 105 if (value == null || value.equals("") || value.equals("${" + name + "}")) { 106 System.setProperty(name, value = def); 107 } 108 return value; 109 } 110 111 protected static String defaultProperty(String name, String def) { 112 String value = System.getProperty(name); 113 if (value == null || value.equals("") || value.equals("${" + name + "}")) { 114 value = def; 115 } 116 Framework.getProperties().setProperty(name, value); 117 return value; 118 } 119 120 protected void init() { 121 changeTokenEnabled = Boolean.parseBoolean( 122 defaultProperty(CHANGE_TOKEN_ENABLED_PROPERTY, CHANGE_TOKEN_ENABLED_DEFAULT)); 123 initJDBC(); 124 switch (coreType) { 125 case CORE_VCS: 126 isVCS = true; 127 break; 128 case CORE_MEM: 129 isDBS = true; 130 break; 131 case CORE_MONGODB: 132 isDBS = true; 133 initMongoDB(); 134 break; 135 default: 136 isDBS = true; 137 initExternal(); 138 } 139 } 140 141 public void initJDBC() { 142 databaseHelper = DatabaseHelper.DATABASE; 143 144 String msg = "Deploying JDBC using " + databaseHelper.getClass().getSimpleName(); 145 // System.out used on purpose, don't remove 146 System.out.println(getClass().getSimpleName() + ": " + msg); 147 log.info(msg); 148 149 // setup system properties for generic XML extension points 150 // this is used both for VCS (org.nuxeo.ecm.core.storage.sql.RepositoryService) 151 // and DataSources (org.nuxeo.runtime.datasource) extension points 152 try { 153 databaseHelper.setUp(); 154 } catch (SQLException e) { 155 throw new NuxeoException(e); 156 } 157 } 158 159 protected void initMongoDB() { 160 String mongoDBServer = defaultProperty(MONGODB_SERVER_PROPERTY, DEFAULT_MONGODB_SERVER); 161 String mongoDBDbName = defaultProperty(MONGODB_DBNAME_PROPERTY, DEFAULT_MONGODB_DBNAME); 162 try (MongoClient mongoClient = MongoDBConnectionHelper.newMongoClient(mongoDBServer)) { 163 MongoDatabase database = mongoClient.getDatabase(mongoDBDbName); 164 database.drop(); 165 } 166 } 167 168 protected void initExternal() { 169 // Get DBSHelper by reflection 170 String className = String.format("org.nuxeo.ecm.core.storage.%s.DBSHelperImpl", coreType); 171 try { 172 dbsHelper = (DBSHelper) Class.forName(className).newInstance(); 173 dbsHelper.init(); 174 } catch (ReflectiveOperationException e) { 175 throw new NuxeoException("DBSHelperImpl not found: " + className, e); 176 } 177 } 178 179 public boolean isVCS() { 180 return isVCS; 181 } 182 183 public boolean isVCSH2() { 184 return isVCS && databaseHelper instanceof DatabaseH2; 185 } 186 187 public boolean isVCSDerby() { 188 return isVCS && databaseHelper instanceof DatabaseDerby; 189 } 190 191 public boolean isVCSPostgreSQL() { 192 return isVCS && databaseHelper instanceof DatabasePostgreSQL; 193 } 194 195 public boolean isVCSMySQL() { 196 return isVCS && databaseHelper instanceof DatabaseMySQL; 197 } 198 199 public boolean isVCSOracle() { 200 return isVCS && databaseHelper instanceof DatabaseOracle; 201 } 202 203 public boolean isVCSSQLServer() { 204 return isVCS && databaseHelper instanceof DatabaseSQLServer; 205 } 206 207 public boolean isVCSDB2() { 208 return isVCS && databaseHelper instanceof DatabaseDB2; 209 } 210 211 public boolean isDBS() { 212 return isDBS; 213 } 214 215 public boolean isDBSMem() { 216 return isDBS && CORE_MEM.equals(coreType); 217 } 218 219 public boolean isDBSMongoDB() { 220 return isDBS && CORE_MONGODB.equals(coreType); 221 } 222 223 public boolean isDBSExternal() { 224 return dbsHelper != null; 225 } 226 227 public boolean isDBSMarkLogic() { 228 return isDBS && CORE_MARKLOGIC.equals(coreType); 229 } 230 231 public String getRepositoryName() { 232 return "test"; 233 } 234 235 /** 236 * For databases that do asynchronous fulltext indexing, sleep a bit. 237 */ 238 public void sleepForFulltext() { 239 if (isVCS()) { 240 databaseHelper.sleepForFulltext(); 241 } else { 242 // DBS 243 } 244 } 245 246 /** 247 * Sleep a bit to get to the next millisecond, to have different timestamps. 248 */ 249 public void maybeSleepToNextSecond() { 250 try { 251 Thread.sleep(1); // 1 millisecond 252 } catch (InterruptedException e) { 253 Thread.currentThread().interrupt(); // restore interrupted status 254 throw new RuntimeException(e); 255 } 256 } 257 258 public void waitForAsyncCompletion() { 259 feature.waitForAsyncCompletion(); 260 } 261 262 public void waitForFulltextIndexing() { 263 waitForAsyncCompletion(); 264 sleepForFulltext(); 265 } 266 267 /** 268 * Checks if the database supports multiple fulltext indexes. 269 */ 270 public boolean supportsMultipleFulltextIndexes() { 271 if (isVCS()) { 272 return databaseHelper.supportsMultipleFulltextIndexes(); 273 } else { 274 return false; // DBS 275 } 276 } 277 278 public List<String> getExternalBundles() { 279 if (isDBSExternal()) { 280 return Arrays.asList(String.format("org.nuxeo.ecm.core.storage.%s", coreType), 281 String.format("org.nuxeo.ecm.core.storage.%s.test", coreType)); 282 } 283 return Collections.emptyList(); 284 } 285 286 public URL getBlobManagerContrib(FeaturesRunner runner) { 287 String bundleName = "org.nuxeo.ecm.core.test"; 288 String contribPath = "OSGI-INF/test-storage-blob-contrib.xml"; 289 RuntimeHarness harness = runner.getFeature(RuntimeFeature.class).getHarness(); 290 Bundle bundle = harness.getOSGiAdapter().getRegistry().getBundle(bundleName); 291 URL contribURL = bundle.getEntry(contribPath); 292 assertNotNull("deployment contrib " + contribPath + " not found", contribURL); 293 return contribURL; 294 } 295 296 public URL getRepositoryContrib(FeaturesRunner runner) { 297 String msg; 298 if (isVCS()) { 299 msg = "Deploying a VCS repository"; 300 } else if (isDBS()) { 301 msg = "Deploying a DBS repository using " + coreType; 302 } else { 303 throw new NuxeoException("Unkown test configuration (not vcs/dbs)"); 304 } 305 // System.out used on purpose, don't remove 306 System.out.println(getClass().getSimpleName() + ": " + msg); 307 log.info(msg); 308 309 String contribPath; 310 String bundleName; 311 if (isVCS()) { 312 bundleName = "org.nuxeo.ecm.core.storage.sql.test"; 313 contribPath = databaseHelper.getDeploymentContrib(); 314 } else { 315 bundleName = "org.nuxeo.ecm.core.test"; 316 if (isDBSMem()) { 317 contribPath = "OSGI-INF/test-storage-repo-mem-contrib.xml"; 318 } else if (isDBSMongoDB()) { 319 contribPath = "OSGI-INF/test-storage-repo-mongodb-contrib.xml"; 320 } else if (isDBSExternal()) { 321 bundleName = String.format("org.nuxeo.ecm.core.storage.%s.test", coreType); 322 contribPath = "OSGI-INF/test-storage-repo-contrib.xml"; 323 } else { 324 throw new NuxeoException("Unkown DBS test configuration (not mem/mongodb)"); 325 } 326 } 327 RuntimeHarness harness = runner.getFeature(RuntimeFeature.class).getHarness(); 328 Bundle bundle = harness.getOSGiAdapter().getRegistry().getBundle(bundleName); 329 URL contribURL = bundle.getEntry(contribPath); 330 assertNotNull("deployment contrib " + contribPath + " not found", contribURL); 331 return contribURL; 332 } 333 334 public boolean isChangeTokenEnabled() { 335 return changeTokenEnabled; 336 } 337 338 /** 339 * @since 9.2 340 */ 341 public String getCoreType() { 342 return coreType; 343 } 344 345}