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