Mercurial > hg > thermostat-ng > agent
changeset 1734:8d3ce721d520
Add compatiblity with mongodb 2.6
Reviewed-by: jerboaa
Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2015-May/013725.html
line wrap: on
line diff
--- a/distribution/config/commands/add-mongodb-user.properties Wed May 20 14:40:55 2015 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -bundles = com.redhat.thermostat.storage.mongodb=${project.version}, \ - org.mongodb.mongo-java-driver=${mongo-driver.osgi-version}, \ - org.apache.commons.beanutils=${commons-beanutils.version}, \ - org.apache.commons.codec=${commons-codec.osgi-version}, \ - org.apache.commons.collections=${commons-collections.version}, \ - org.apache.commons.logging=${commons-logging.version} - -summary = add a new mongodb user to the thermostat DB - -description = Add a new mongodb user to the thermostat DB, reading credentials \ - from standard input. - -usage = add-mongodb-user -d <dbUrl> |\ - add-mongodb-user -s - -options = AUTO_LOG_OPTION, AUTO_DB_OPTIONS, startStorage - -startStorage.short = s -startStorage.long = startStorage -startStorage.description = start storage with appropriate options before \ - running the command and stop the storage when the command finishes -startStorage.required = false -startStorage.hasarg = false - -environments = cli
--- a/distribution/scripts/thermostat-setup Wed May 20 14:40:55 2015 -0400 +++ b/distribution/scripts/thermostat-setup Thu May 21 15:36:44 2015 -0400 @@ -283,15 +283,40 @@ echo -e "connections.\n" readUsername "$defaultName" readPassword - setupCmdName="add-mongodb-user -s" - output="$(echo -e $USERNAME\\n$PASSWORD\\n | $THERMOSTAT $setupCmdName 2>&1)" - # The above should have created the mongodb stamp file - monogdbSetupStampFile="$USER_THERMOSTAT_HOME/data/mongodb-user-done.stamp" - if [ ! -e "$monogdbSetupStampFile" ] || - ! echo $output | grep -s "setup complete" > /dev/null; then + mkdir -p "$USER_THERMOSTAT_HOME"/data/db/ + mkdir -p "$USER_THERMOSTAT_HOME"/logs/ + mkdir -p "$USER_THERMOSTAT_HOME"/run/ + mkdir -p "$USER_THERMOSTAT_HOME"/etc/ + mkdir -p "$USER_THERMOSTAT_HOME"/cache/ + mongod --nojournal \ + --quiet \ + --fork \ + --noauth \ + --nohttpinterface \ + --bind_ip 127.0.0.1 \ + --port 27518 \ + --dbpath "$USER_THERMOSTAT_HOME"/data/db \ + --logpath "$USER_THERMOSTAT_HOME"/logs/db.log \ + --pidfilepath "$USER_THERMOSTAT_HOME"/run/db.pid + MONGOD_RETVAL="$?" + if [ "$MONGOD_RETVAL" -ne 0 ] ; then echo -e "\nMongodb user setup failed." 1>&2 exitFail fi + sleep 5 + mongo 127.0.0.1:27518 << EOF +use thermostat +db.addUser({ user: "$USERNAME", pwd: "$PASSWORD", roles: [ "readWrite" ] }) +use admin +db.shutdownServer() +quit() +EOF + MONGO_SETUP_RETVAL="$?" + if [ "$MONGO_SETUP_RETVAL" -ne 0 ] ; then + echo -e "\nMongodb user setup failed." 1>&2 + exitFail + fi + touch "$USER_THERMOSTAT_HOME"/data/mongodb-user-done.stamp } doProceedLoop() {
--- a/integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/IntegrationTest.java Wed May 20 14:40:55 2015 -0400 +++ b/integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/IntegrationTest.java Thu May 21 15:36:44 2015 -0400 @@ -146,6 +146,21 @@ } } + protected static void createFakeUserSetupDoneFile() { + String userHome = getUserThermostatHome(); + File fUserHome = new File(userHome); + fUserHome.mkdir(); + File dataDir = new File(fUserHome, "data"); + dataDir.mkdir(); + + File mongodbUserDoneFile = new File(dataDir, "mongodb-user-done.stamp"); + try { + // creates the file only if not yet existing + mongodbUserDoneFile.createNewFile(); + } catch (IOException e) { + throw new RuntimeException(e.getMessage(), e); + } + } /** * Utility method for removing stamp files which may get created by certain @@ -245,8 +260,6 @@ } public static Spawn startStorage() throws Exception { - clearStorageDataDirectory(); - Spawn storage = spawnThermostat("storage", "--start", "--permitLocalhostException"); try { storage.expect("pid:");
--- a/integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/MongoQueriesTest.java Wed May 20 14:40:55 2015 -0400 +++ b/integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/MongoQueriesTest.java Thu May 21 15:36:44 2015 -0400 @@ -68,9 +68,9 @@ import com.redhat.thermostat.storage.core.Cursor; import com.redhat.thermostat.storage.core.Key; import com.redhat.thermostat.storage.core.Query; -import com.redhat.thermostat.storage.core.StorageCredentials; import com.redhat.thermostat.storage.core.Query.SortDirection; import com.redhat.thermostat.storage.core.Storage; +import com.redhat.thermostat.storage.core.StorageCredentials; import com.redhat.thermostat.storage.mongodb.internal.MongoStorage; import com.redhat.thermostat.storage.query.Expression; import com.redhat.thermostat.storage.query.ExpressionFactory; @@ -123,6 +123,7 @@ @BeforeClass public static void setUpOnce() throws Exception { createFakeSetupCompleteFile(); + clearStorageDataDirectory(); startStorage(); addCpuData(4);
--- a/integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/StorageConnectionTest.java Wed May 20 14:40:55 2015 -0400 +++ b/integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/StorageConnectionTest.java Thu May 21 15:36:44 2015 -0400 @@ -51,6 +51,7 @@ // @BeforeClass // reinstate once we actually need storage running (see ignored tests) public static void setUpOnce() throws Exception { + clearStorageDataDirectory(); startStorage(); }
--- a/integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/StorageTest.java Wed May 20 14:40:55 2015 -0400 +++ b/integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/StorageTest.java Thu May 21 15:36:44 2015 -0400 @@ -59,8 +59,9 @@ @Test public void startAndStopStorage() throws Exception { + clearStorageDataDirectory(); + Spawn storage; - storage = startStorage(); storage = spawnThermostat("storage", "--status");
--- a/integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/VmCommandsTest.java Wed May 20 14:40:55 2015 -0400 +++ b/integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/VmCommandsTest.java Thu May 21 15:36:44 2015 -0400 @@ -54,6 +54,7 @@ @BeforeClass public static void setUpOnce() throws Exception { createFakeSetupCompleteFile(); + clearStorageDataDirectory(); startStorage(); // TODO insert actual data into the database and test that
--- a/integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/WebAppTest.java Wed May 20 14:40:55 2015 -0400 +++ b/integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/WebAppTest.java Thu May 21 15:36:44 2015 -0400 @@ -47,6 +47,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; @@ -57,10 +58,12 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.NoSuchElementException; import java.util.Properties; import java.util.Set; import java.util.UUID; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import org.eclipse.jetty.server.Server; @@ -110,9 +113,9 @@ import com.redhat.thermostat.web.client.internal.WebStorage; import com.redhat.thermostat.web.server.auth.Roles; +import expectj.ExpectJ; import expectj.Spawn; import expectj.TimeoutException; -import java.util.NoSuchElementException; /** * This test class starts up a mongod instance and a web storage instance @@ -240,6 +243,7 @@ private static final double EQUALS_DELTA = 0.00000000000001; private static final String THERMOSTAT_USERS_FILE = getConfigurationDir() + "/thermostat-users.properties"; private static final String THERMOSTAT_ROLES_FILE = getConfigurationDir() + "/thermostat-roles.properties"; + private static final String THERMOSTAT_WEB_AUTH_FILE = getThermostatHome() + "/webapp/WEB-INF/web.auth"; private static final String VM_ID1 = "vmId1"; private static final String VM_ID2 = "vmId2"; private static final String VM_ID3 = "vmId3"; @@ -248,25 +252,41 @@ private static int port; private static Path backupUsers; private static Path backupRoles; + private static Path backupWebAuth; @BeforeClass public static void setUpOnce() throws Exception { - - // This starts storage with the permit localhost exception option. - // It's important to start storage with that exception. Otherwise the - // mongodb user creds setup will fail. - createFakeSetupCompleteFile(); - startStorage(); - - setupMongodbUser(); + clearStorageDataDirectory(); backupUsers = Files.createTempFile("itest-backup-thermostat-users", ""); backupRoles = Files.createTempFile("itest-backup-thermostat-roles", ""); + backupWebAuth = Files.createTempFile("itest-backup-webapp-auth", ""); backupRoles.toFile().deleteOnExit(); backupUsers.toFile().deleteOnExit(); + backupWebAuth.toFile().deleteOnExit(); Files.copy(new File(THERMOSTAT_USERS_FILE).toPath(), backupUsers, StandardCopyOption.REPLACE_EXISTING); Files.copy(new File(THERMOSTAT_ROLES_FILE).toPath(), backupRoles, StandardCopyOption.REPLACE_EXISTING); + Files.copy(new File(THERMOSTAT_WEB_AUTH_FILE).toPath(), backupWebAuth, StandardCopyOption.REPLACE_EXISTING); + createFakeSetupCompleteFile(); + createFakeUserSetupDoneFile(); + + setupMongodbUser(); + + startStorage(); + + ExpectJ mongo = new ExpectJ(TIMEOUT_IN_SECONDS); + Spawn mongoSpawn = mongo.spawn("mongo 127.0.0.1:27518"); + mongoSpawn.send("use thermostat\n"); + mongoSpawn.expect("switched to db thermostat"); + mongoSpawn.send(String.format("db.auth(\"%s\", \"%s\")\n", getMongodbUsername(), getMongodbPassword())); + mongoSpawn.expect("1"); + mongoSpawn.send("db[\"fake\"].insert({foo:\"bar\", baz: 1})\n"); + mongoSpawn.send("db[\"fake\"].findOne()\n"); + mongoSpawn.send("show collections\n"); + mongoSpawn.send("show users\n"); + + createWebAuthFile(); // start the server, deploy the war port = FreePortFinder.findFreePort(new TryPort() { @@ -282,59 +302,118 @@ @AfterClass public static void tearDownOnce() throws Exception { - deleteCpuData(); - - server.stop(); - server.join(); + try { + deleteCpuData(); - stopStorage(); - removeSetupCompleteStampFiles(); - - Files.copy(backupUsers, new File(THERMOSTAT_USERS_FILE).toPath(), StandardCopyOption.REPLACE_EXISTING); - Files.copy(backupRoles, new File(THERMOSTAT_ROLES_FILE).toPath(), StandardCopyOption.REPLACE_EXISTING); + server.stop(); + server.join(); + + stopStorage(); + removeSetupCompleteStampFiles(); + } catch (Exception e) { + System.out.println("AN ERROR OCCURRED!"); + e.printStackTrace(); + throw e; + } finally { + Files.copy(backupUsers, new File(THERMOSTAT_USERS_FILE).toPath(), StandardCopyOption.REPLACE_EXISTING); + Files.copy(backupRoles, new File(THERMOSTAT_ROLES_FILE).toPath(), StandardCopyOption.REPLACE_EXISTING); + Files.copy(backupWebAuth, new File(THERMOSTAT_WEB_AUTH_FILE).toPath(), StandardCopyOption.REPLACE_EXISTING); + System.out.println("RESTORED web.auth!"); + } } // PRE: storage started with --permitLocalhostException private static void setupMongodbUser() throws Exception { - // The actual setup is only required for devel builds. - // Release builds won't have a web.xml with actual username/passwords - // in it, so starting backing storage (i.e. mongodb) with the - // --permitLocalhostException option is sufficient. + // The actual setup is only required for devel builds. Release builds + // won't have users or roles configured, so starting backing storage + // (i.e. mongodb) with the --permitLocalhostException option is + // sufficient. + if (isDevelopmentBuild()) { - - // Remove the mongodb-user-added.stamp file, - // but keep the main setup file around so as to be able to - // actually launch thermostat. - removeSetupCompleteStampFiles(); - createFakeSetupCompleteFile(); - String mongodbUsername = getMongodbUsername(); String mongodbPassword = getMongodbPassword(); - String creds = String.format("%s\n%s\n", mongodbUsername, - mongodbPassword); - String[] addUserArgs = new String[] { - "add-mongodb-user", - "-d", "mongodb://127.0.0.1:27518" - }; - - // This should be an equivalent of: - // $ echo -e "mongodbUsername\nmongodbPassword\n" | \ - // thermostat add-mongodb-user -d mongodb://127.0.0.1:27518 - Spawn addUser = spawnThermostat(addUserArgs); - addUser.send(creds); + + final String HOST = "127.0.0.1"; + final String PORT = "27518"; + try { - addUser.expect("mongodb user setup complete"); + System.out.println("THERMOSTAT_HOME: " + getThermostatHome()); + System.out.println("USER_THERMOSTAT_HOME: " + getUserThermostatHome()); + + // create directories that we use later down to store stuff in + // things fail silently if the directories do not exist + new File(getUserThermostatHome() + "/data/db").mkdirs(); + new File(getUserThermostatHome() + "/logs/").mkdirs(); + new File(getUserThermostatHome() + "/run/").mkdirs(); + new File(getUserThermostatHome() + "/etc/").mkdirs(); + new File(getUserThermostatHome() + "/cache/").mkdirs(); + + ExpectJ mongod = new ExpectJ(TIMEOUT_IN_SECONDS); + final String MONGOD_COMMAND = "mongod " + + "--quiet " + + "--fork " + + "--noauth " + + "--nohttpinterface " + + "--bind_ip " + HOST + " " + + "--port " + PORT + " " + + "--dbpath " + getUserThermostatHome() + "/data/db " + + "--logpath " + getUserThermostatHome() + "/logs/db.log " + + "--pidfilepath " + getUserThermostatHome() + "/run/db.pid"; + System.out.println(MONGOD_COMMAND); + Spawn mongodSpawn = mongod.spawn(MONGOD_COMMAND); + mongodSpawn.expectClose(TIMEOUT_IN_SECONDS); + + System.out.println("Started mongod"); + TimeUnit.SECONDS.sleep(5); + + ExpectJ mongo = new ExpectJ(TIMEOUT_IN_SECONDS); + Spawn mongoSpawn = mongo.spawn("mongo " + HOST + ":" + PORT); + mongoSpawn.send("use thermostat\n"); + mongoSpawn.send(String.format("db.addUser({ user: \"%s\", pwd: \"%s\", roles: [ \"readWrite\" ] })\n", + mongodbUsername, mongodbPassword)); + mongoSpawn.send("quit()\n"); + mongoSpawn.expectClose(); + + mongo = new ExpectJ(TIMEOUT_IN_SECONDS); + mongoSpawn = mongo.spawn("mongo " + HOST + ":" + PORT); + mongoSpawn.send("use thermostat\n"); + mongoSpawn.expect("switched to db thermostat"); + mongoSpawn.send(String.format("db.auth(\"%s\", \"%s\")\n", mongodbUsername, mongodbPassword)); + mongoSpawn.expect("1"); + + // now insert some fake data and display some information that + // might be useful for post-mortem analysis if this test fails + mongoSpawn.send("db[\"fake\"].insert({foo:\"bar\", baz: 1})\n"); + mongoSpawn.send("db[\"fake\"].findOne()\n"); + mongoSpawn.send("show collections\n"); + mongoSpawn.send("show users\n"); + + mongoSpawn.send("use admin\n"); + mongoSpawn.expect("switched to db admin"); + mongoSpawn.send("db.shutdownServer()\n"); + mongoSpawn.send("quit()\n"); + mongoSpawn.expectClose(); + } catch (TimeoutException | IOException e) { - // failed to set up mongodb user, stop storage and bail. - stopStorage(); throw e; } - addUser.expectClose(); } else { System.out.println("Not a development build. Skipping mongodb setup."); } } + private static void createWebAuthFile() throws IOException { + if (isDevelopmentBuild()) { + System.out.println("WRITING auth file: " + getMongodbUsername() + "/" + getMongodbPassword()); + List<String> lines = new ArrayList<String>(); + lines.add("storage.username = " + getMongodbUsername()); + lines.add("storage.password = " + getMongodbPassword()); + Files.write(new File(THERMOSTAT_WEB_AUTH_FILE).toPath(), lines, StandardCharsets.UTF_8); + } else { + throw new AssertionError("testing a build !"); + } + } + private static String getMongodbUsername() { assertTrue(isDevelopmentBuild()); @@ -366,12 +445,12 @@ @Override public String getUsername() { - return null; + return getMongodbUsername(); } @Override public char[] getPassword() { - return null; + return getMongodbPassword().toCharArray(); } };
--- a/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/Activator.java Wed May 20 14:40:55 2015 -0400 +++ b/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/Activator.java Thu May 21 15:36:44 2015 -0400 @@ -40,8 +40,6 @@ import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; -import com.redhat.thermostat.common.cli.CommandRegistry; -import com.redhat.thermostat.common.cli.CommandRegistryImpl; import com.redhat.thermostat.storage.core.StorageProvider; import com.redhat.thermostat.storage.mongodb.MongoStorageProvider; @@ -49,20 +47,16 @@ @SuppressWarnings("rawtypes") private ServiceRegistration reg; - private CommandRegistry cmdReg; @Override public void start(BundleContext context) throws Exception { StorageProvider prov = new MongoStorageProvider(); reg = context.registerService(StorageProvider.class.getName(), prov, null); - cmdReg = new CommandRegistryImpl(context); - cmdReg.registerCommand(AddUserCommandDispatcher.COMMAND_NAME, new AddUserCommandDispatcher(context)); } @Override public void stop(BundleContext context) throws Exception { reg.unregister(); - cmdReg.unregisterCommands(); } }
--- a/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/AddUserCommand.java Wed May 20 14:40:55 2015 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,198 +0,0 @@ -/* - * Copyright 2012-2015 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.storage.mongodb.internal; - -import java.io.File; -import java.io.IOException; -import java.lang.reflect.Field; -import java.util.Arrays; -import java.util.Objects; - -import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceReference; -import org.osgi.framework.ServiceRegistration; - -import com.redhat.thermostat.common.cli.CommandContext; -import com.redhat.thermostat.common.cli.CommandException; -import com.redhat.thermostat.common.tools.StorageAuthInfoGetter; -import com.redhat.thermostat.shared.config.CommonPaths; -import com.redhat.thermostat.shared.locale.LocalizedString; -import com.redhat.thermostat.shared.locale.Translate; -import com.redhat.thermostat.storage.core.DbService; -import com.redhat.thermostat.storage.core.DbServiceFactory; -import com.redhat.thermostat.storage.core.QueuedStorage; -import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.core.StorageCredentials; - -/** - * This command needs to be in the mongodb storage bundle since it - * uses MongoStorage directly (casts to it). - * - */ -public class AddUserCommand extends BaseAddUserCommand { - - private static final Translate<LocaleResources> t = LocaleResources.createLocalizer(); - static final String DB_URL_ARG = "dbUrl"; - private final BundleContext context; - private final StorageCredentials emptyCredentials; - - AddUserCommand(BundleContext context) { - this.context = context; - // These are empty credentials we'll use for the initial connect. We - // connect with them when the local host exception is turned off. - emptyCredentials = new StorageCredentials() { - - @Override - public String getUsername() { - return null; - } - - @Override - public char[] getPassword() { - return null; - } - }; - } - - // PRE: storage started with --permitLocalHostException. - // FIXME: Is there anything we can do to ensure this precondition? - @Override - public void run(CommandContext ctx) throws CommandException { - // Check if mongodb stamp file exists. - ServiceReference commonPathRef = context.getServiceReference(CommonPaths.class.getName()); - requireNonNull(commonPathRef, t.localize(LocaleResources.COMMON_PATHS_SERVICE_UNAVAILABLE)); - CommonPaths commonPath = (CommonPaths)context.getService(commonPathRef); - File dataDir = commonPath.getUserPersistentDataDirectory(); - // Since this is backing storage specific, it's most likely not a good - // candidate for CommonPaths - File mongodbSetupStamp = new File(dataDir, BaseAddUserCommand.MONGODB_STAMP_FILE_NAME); - if (mongodbSetupStamp.exists()) { - String msg = t.localize(LocaleResources.MONGODB_SETUP_FILE_EXISTS, - mongodbSetupStamp.getAbsolutePath()).getContents(); - ctx.getConsole().getOutput().println(msg); - return; - } - - ServiceReference dbServiceRef = context.getServiceReference(DbService.class); - if (dbServiceRef != null) { - // Already connected, bail out - throw new CommandException(t.localize(LocaleResources.ALREADY_CONNECTED_TO_STORAGE_WARNING)); - } - String dbUrl = ctx.getArguments().getArgument(DB_URL_ARG); - // dbUrl is a required argument. This should never happen - Objects.requireNonNull(dbUrl); - // we only understand "mongodb://" URLs - if (!dbUrl.startsWith("mongodb://")) { - throw new CommandException(t.localize(LocaleResources.UNKNOWN_STORAGE_URL)); - } - - // Register empty credentials so that connection succeeds - ServiceRegistration reg = context.registerService(StorageCredentials.class.getName(), emptyCredentials, null); - DbServiceFactory factory = new DbServiceFactory(); - DbService service = factory.createDbService(dbUrl); - // this synchronously connects to storage - service.connect(); - // Unregister empty credentials - reg.unregister(); - - ServiceReference storageRef = context.getServiceReference(Storage.class.getName()); - requireNonNull(storageRef, t.localize(LocaleResources.STORAGE_SERVICE_UNAVAILABLE)); - @SuppressWarnings("unchecked") - // FIXME: Hack alarm. We use knowledge that via MongoStorageProvider we - // have a MongoStorage instance wrapped in QueuedStorage. What's - // more, we use the "delegate" field name in order to get at the - // MongoStorage instance, which we cast to. I'm not sure if adding - // method in BackingStorage (the interface) directly would be - // any better than this. After all, this is very backing storage - // impl specific. For now do this hack :-/ - QueuedStorage storage = (QueuedStorage)context.getService(storageRef); - MongoStorage mongoStorage = getDelegate(storage); - requireNonNull(mongoStorage, t.localize(LocaleResources.MONGOSTORAGE_RETRIEVAL_FAILED)); - StorageAuthInfoGetter getter = null; - try { - LocalizedString userPrompt = new LocalizedString("Please enter the username you'd like to add to mongodb storage at " + dbUrl + ": "); - LocalizedString passWordPrompt = new LocalizedString("Please enter the desired password of this user: "); - getter = new StorageAuthInfoGetter(ctx.getConsole(), userPrompt, passWordPrompt); - } catch (IOException e) { - throw new CommandException(t.localize(LocaleResources.ADDING_USER_FAILED)); - } - ConsoleStorageCredentials creds = new ConsoleStorageCredentials(getter); - addUser(mongoStorage, creds); - - // create the STAMP file - try { - mongodbSetupStamp.createNewFile(); - } catch (IOException e) { - String msg = t.localize(LocaleResources.STAMP_FILE_CREATION_FAILED, - mongodbSetupStamp.getAbsolutePath()).getContents(); - ctx.getConsole().getError().println(msg); - throw new CommandException(new LocalizedString(msg)); - } - - String msg = t.localize(LocaleResources.MONGODB_USER_SETUP_COMPLETE).getContents(); - ctx.getConsole().getOutput().println(msg); - } - - // package-private for testing - void addUser(MongoStorage mongoStorage, StorageCredentials creds) { - // It's important that getUsername is called prior getPassword. - // otherwise prompts don't make much sense. - String username = creds.getUsername(); - char[] pwd = creds.getPassword(); - mongoStorage.addUser(username, pwd); - // zero out password. We no longer use it. - Arrays.fill(pwd, '\0'); - } - - // package-private for testing - MongoStorage getDelegate(QueuedStorage storage) { - try { - Field field = storage.getClass().getDeclaredField("delegate"); - field.setAccessible(true); - MongoStorage mongo = (MongoStorage)field.get(storage); - return mongo; - } catch (Exception e) { - return null; - } - } - - @Override - public boolean isStorageRequired() { - return false; - } - -}
--- a/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/AddUserCommandDispatcher.java Wed May 20 14:40:55 2015 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +0,0 @@ -/* - * Copyright 2012-2015 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.storage.mongodb.internal; - -import org.osgi.framework.BundleContext; - -import com.redhat.thermostat.common.cli.CommandContext; -import com.redhat.thermostat.common.cli.CommandException; -import com.redhat.thermostat.shared.locale.Translate; - -/** - * Dispatcher making sure either -d or -s has been provided. - * - */ -class AddUserCommandDispatcher extends BaseAddUserCommand { - - private static final Translate<LocaleResources> t = LocaleResources.createLocalizer(); - private static final String START_STORAGE_ARG = "startStorage"; - private static final String DB_URL_ARG = "dbUrl"; - static final String COMMAND_NAME = "add-mongodb-user"; - private final BundleContext context; - private BaseAddUserCommand command; - - AddUserCommandDispatcher(BundleContext context, BaseAddUserCommand cmd) { - this.context = context; - this.command = cmd; - } - - AddUserCommandDispatcher(BundleContext context) { - this(context, new AddUserCommand(context)); - } - - @Override - public void run(CommandContext ctx) throws CommandException { - if (ctx.getArguments().hasArgument(START_STORAGE_ARG)) { - // decorate and run - command = new StartStopAddUserCommandDecorator(context, command); - } else if (!ctx.getArguments().hasArgument(DB_URL_ARG)) { - throw new CommandException(t.localize(LocaleResources.DISPATCHER_WRONG_OPTION)); - } - command.run(ctx); - } - -}
--- a/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/BaseAddUserCommand.java Wed May 20 14:40:55 2015 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -/* - * Copyright 2012-2015 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.storage.mongodb.internal; - -import com.redhat.thermostat.common.cli.AbstractCommand; -import com.redhat.thermostat.common.cli.CommandContext; -import com.redhat.thermostat.common.cli.CommandException; - -/** - * - * Base class for user setup decorators. - * - * @see AddUserCommand - * @see StartStopAddUserCommandDecorator - * - */ -abstract class BaseAddUserCommand extends AbstractCommand { - - static final String MONGODB_STAMP_FILE_NAME = "mongodb-user-done.stamp"; - - @Override - abstract public void run(CommandContext ctx) throws CommandException; - - @Override - public boolean isStorageRequired() { - return false; - } -}
--- a/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoConnection.java Wed May 20 14:40:55 2015 -0400 +++ b/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoConnection.java Thu May 21 15:36:44 2015 -0400 @@ -115,7 +115,7 @@ private void authenticate(String username, char[] password) { if (! db.authenticate(username, password)) { - throw new MongoException("Invalid username/password"); + throw new MongoException("Invalid username/password: " + username + "/" + new String(password)); } }
--- a/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorage.java Wed May 20 14:40:55 2015 -0400 +++ b/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorage.java Thu May 21 15:36:44 2015 -0400 @@ -703,18 +703,6 @@ categoryInfo, true, false); } - - /* - * Used by add-user command. - * - * Pre: must be connected to storage already - */ - void addUser(String username, char[] password) { - // only create user if not already existing - if (!db.authenticate(username, password)) { - db.addUser(username, password); - } - } }
--- a/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/StartStopAddUserCommandDecorator.java Wed May 20 14:40:55 2015 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,268 +0,0 @@ -/* - * Copyright 2012-2015 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.storage.mongodb.internal; - -import java.io.File; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.CountDownLatch; - -import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceReference; - -import com.redhat.thermostat.common.ActionEvent; -import com.redhat.thermostat.common.ActionListener; -import com.redhat.thermostat.common.cli.AbstractStateNotifyingCommand; -import com.redhat.thermostat.common.cli.Arguments; -import com.redhat.thermostat.common.cli.CommandContext; -import com.redhat.thermostat.common.cli.CommandContextFactory; -import com.redhat.thermostat.common.cli.CommandException; -import com.redhat.thermostat.common.tools.ApplicationState; -import com.redhat.thermostat.launcher.Launcher; -import com.redhat.thermostat.shared.config.CommonPaths; -import com.redhat.thermostat.shared.locale.Translate; - -/* - * A command which adds a mongdb user by using AddUserCommand. It has been - * introduced in order to aid boot-strapping of thermostat deployments. In order - * to set up a user in mongodb, storage needs to be started with the - * --permitLocalhostException option first. Then the credentials need to be - * injected and storage stopped again. This command performs all three - * required steps. - */ -public class StartStopAddUserCommandDecorator extends BaseAddUserCommand { - - public static final String COMMAND_NAME = "admin-mongodb-creds-setup"; - private static final Translate<LocaleResources> t = LocaleResources.createLocalizer(); - private final BundleContext context; - private final List<ActionListener<ApplicationState>> listeners; - private final CountDownLatch setupFinishedBarrier; - private final BaseAddUserCommand decoratee; - private boolean setupSuccessful; - private Launcher launcher; - private CommandContext cmdCtx; - - StartStopAddUserCommandDecorator(BundleContext context, BaseAddUserCommand command) { - this.context = context; - this.listeners = new ArrayList<>(1); - this.setupFinishedBarrier = new CountDownLatch(1); - this.setupSuccessful = true; - this.decoratee = command; - } - - @Override - public void run(CommandContext ctx) throws CommandException { - cmdCtx = ctx; - if (!stampFileExists()) { - startStorageAndRunDecoratee(); - stopStorage(); - } - // if stamp file exists, there is nothing to do. - String msg; - if (setupSuccessful) { - msg = t.localize(LocaleResources.USER_SETUP_COMPLETE).getContents(); - cmdCtx.getConsole().getOutput().println(msg); - } else { - msg = t.localize(LocaleResources.USER_SETUP_FAILED).getContents(); - cmdCtx.getConsole().getOutput().println(msg); - } - } - - private void stopStorage() throws CommandException { - listeners.clear(); - CountDownLatch storageStoppedlatch = new CountDownLatch(1); - StorageStoppedListener listener = new StorageStoppedListener(storageStoppedlatch); - String[] storageStopArgs = new String[] { - "storage", "--stop" - }; - listeners.add(listener); - launcher.run(storageStopArgs, listeners, false); - try { - storageStoppedlatch.await(); - } catch (InterruptedException e) { - setupSuccessful = false; - throw new CommandException(t.localize(LocaleResources.INTERRUPTED_WAITING_FOR_STORAGE_STOP), e); - } - if (!listener.storageStopPassed) { - setupSuccessful = false; - String msg = t.localize(LocaleResources.STORAGE_STOP_FAILED).getContents(); - cmdCtx.getConsole().getError().println(msg); - } - } - - private void startStorageAndRunDecoratee() throws CommandException { - ServiceReference launcherRef = context.getServiceReference(Launcher.class); - if (launcherRef == null) { - throw new CommandException(t.localize(LocaleResources.LAUNCHER_SERVICE_UNAVAILABLE)); - } - launcher = (Launcher) context.getService(launcherRef); - StorageStartedListener listener = new StorageStartedListener(); - listeners.add(listener); - String[] storageStartArgs = new String[] { "storage", "--start", "--permitLocalhostException"}; - launcher.run(storageStartArgs, listeners, false); - try { - setupFinishedBarrier.await(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - - private boolean stampFileExists() throws CommandException { - ServiceReference commonPathRef = context.getServiceReference(CommonPaths.class.getName()); - if (commonPathRef == null) { - throw new CommandException(t.localize(LocaleResources.COMMON_PATHS_SERVICE_UNAVAILABLE)); - } - CommonPaths commonPath = (CommonPaths)context.getService(commonPathRef); - File dataDir = commonPath.getUserPersistentDataDirectory(); - // Since this is backing storage specific, it's most likely not a good - // candidate for CommonPaths - File mongodbSetupStamp = new File(dataDir, BaseAddUserCommand.MONGODB_STAMP_FILE_NAME); - if (mongodbSetupStamp.exists()) { - String msg = t.localize(LocaleResources.MONGODB_SETUP_FILE_EXISTS, - mongodbSetupStamp.getAbsolutePath()).getContents(); - cmdCtx.getConsole().getOutput().println(msg); - return true; - } else { - return false; - } - } - - private class StorageStartedListener implements ActionListener<ApplicationState> { - - @Override - public void actionPerformed(ActionEvent<ApplicationState> actionEvent) { - if (actionEvent.getSource() instanceof AbstractStateNotifyingCommand) { - AbstractStateNotifyingCommand storage = (AbstractStateNotifyingCommand) actionEvent.getSource(); - // Implementation detail: there is a single StorageCommand instance registered - // as an OSGi service. We remove ourselves as listener so that we don't get - // notified in the case that the command is invoked by some other means later. - storage.getNotifier().removeActionListener(this); - - try { - switch (actionEvent.getActionId()) { - case START: - // Payload is connection URL - Object payload = actionEvent.getPayload(); - if (payload == null || !(payload instanceof String)) { - setupSuccessful = false; - throw new CommandException(t.localize(LocaleResources.UNRECOGNIZED_PAYLOAD_FROM_STORAGE_CMD)); - } - final String dbUrl = (String)payload; - try { - CommandContext ctx = getAddUserCommandContext(dbUrl); - decoratee.run(ctx); - } catch (CommandException e) { - cmdCtx.getConsole().getError().println(e.getMessage()); - String msg = t.localize(LocaleResources.ADDING_USER_FAILED).getContents(); - cmdCtx.getConsole().getError().println(msg); - } - break; - case FAIL: - // nothing - break; - default: - // nothing - break; - } - } catch (CommandException e) { - cmdCtx.getConsole().getError().println(e.getMessage()); - } finally { - setupFinishedBarrier.countDown(); - } - } - - } - - private CommandContext getAddUserCommandContext(final String dbUrl) { - CommandContextFactory factory = new CommandContextFactory(context); - CommandContext ctx = factory.createContext(new Arguments() { - - @Override - public boolean hasArgument(String name) { - if (name.equals(AddUserCommand.DB_URL_ARG)) { - return true; - } - return false; - } - - @Override - public List<String> getNonOptionArguments() { - return Collections.emptyList(); - } - - @Override - public String getArgument(String name) { - if (name.equals(AddUserCommand.DB_URL_ARG)) { - return dbUrl; - } - return null; - } - }); - return ctx; - } - } - - private static class StorageStoppedListener implements ActionListener<ApplicationState> { - - private boolean storageStopPassed; - private final CountDownLatch storageStoppedLatch; - private StorageStoppedListener(CountDownLatch latch) { - storageStoppedLatch = latch; - } - - @Override - public void actionPerformed(ActionEvent<ApplicationState> actionEvent) { - if (actionEvent.getSource() instanceof AbstractStateNotifyingCommand) { - AbstractStateNotifyingCommand storage = (AbstractStateNotifyingCommand) actionEvent.getSource(); - // remove ourselves so that we get called more than once. - storage.getNotifier().removeActionListener(this); - switch(actionEvent.getActionId()) { - case STOP: - storageStopPassed = true; - storageStoppedLatch.countDown(); - break; - default: - storageStoppedLatch.countDown(); - break; - - } - } - } - - } -}
--- a/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/AddUserCommandDispatcherTest.java Wed May 20 14:40:55 2015 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,119 +0,0 @@ -/* - * Copyright 2012-2015 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.storage.mongodb.internal; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.eq; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import org.junit.Test; -import org.osgi.framework.BundleContext; - -import com.redhat.thermostat.common.cli.Arguments; -import com.redhat.thermostat.common.cli.CommandContext; -import com.redhat.thermostat.common.cli.CommandContextFactory; -import com.redhat.thermostat.common.cli.CommandException; - -public class AddUserCommandDispatcherTest { - - @Test - public void canRunUndecorated() { - BundleContext context = mock(BundleContext.class); - BaseAddUserCommand mockCmd = mock(BaseAddUserCommand.class); - AddUserCommandDispatcher dispatcher = new AddUserCommandDispatcher(context, mockCmd); - CommandContextFactory factory = new CommandContextFactory(context); - Arguments args = mock(Arguments.class); - when(args.hasArgument(eq("dbUrl"))).thenReturn(true); - CommandContext ctx = factory.createContext(args); - - // This should not throw any exception - try { - dispatcher.run(ctx); - } catch (CommandException e) { - fail(e.getMessage()); - } - } - - @Test(expected = CommandException.class ) - public void failsToRunWithNoArguments() throws CommandException { - BundleContext context = mock(BundleContext.class); - BaseAddUserCommand mockCmd = mock(BaseAddUserCommand.class); - AddUserCommandDispatcher dispatcher = new AddUserCommandDispatcher(context, mockCmd); - CommandContextFactory factory = new CommandContextFactory(context); - Arguments args = mock(Arguments.class); - when(args.hasArgument(any(String.class))).thenReturn(false); - CommandContext ctx = factory.createContext(args); - - // this throws CommandException - dispatcher.run(ctx); - } - - @Test - public void decoratesIfStorageStartOptionGiven() { - BundleContext context = mock(BundleContext.class); - BaseAddUserCommand mockCmd = mock(BaseAddUserCommand.class); - AddUserCommandDispatcher dispatcher = new AddUserCommandDispatcher(context, mockCmd); - CommandContextFactory factory = new CommandContextFactory(context); - Arguments args = mock(Arguments.class); - when(args.hasArgument(eq("startStorage"))).thenReturn(true); - CommandContext ctx = factory.createContext(args); - - try { - dispatcher.run(ctx); - fail("CommonPaths not available, should have thrown exception"); - } catch (CommandException e) { - boolean passed = false; - for( StackTraceElement elmt: e.getStackTrace()) { - // StartStopAddUserCommandDecorator should be in stack trace - if (elmt.getClassName().equals(StartStopAddUserCommandDecorator.class.getName())) { - passed = true; - break; - } - } - assertTrue("Expected mocked BaseAddUserCommand to be decorated", passed); - } - } - - @Test - public void testCommandName() { - assertEquals("add-mongodb-user", AddUserCommandDispatcher.COMMAND_NAME); - } -}
--- a/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/AddUserCommandTest.java Wed May 20 14:40:55 2015 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,116 +0,0 @@ -/* - * Copyright 2012-2015 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.storage.mongodb.internal; - -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.util.Arrays; -import java.util.concurrent.CountDownLatch; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.InOrder; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PowerMockIgnore; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; - -import com.mongodb.DB; -import com.redhat.thermostat.storage.core.QueuedStorage; -import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.core.StorageCredentials; - -//There is a bug (resolved as wontfix) in powermock which results in -//java.lang.LinkageError if javax.management.* classes aren't ignored by -//Powermock. More here: http://code.google.com/p/powermock/issues/detail?id=277 -//SSL tests need this and having that annotation on method level doesn't seem -//to solve the issue. -@PowerMockIgnore( {"javax.management.*"}) -@RunWith(PowerMockRunner.class) -@PrepareForTest({ DB.class }) -public class AddUserCommandTest { - - /* - * Verifies that credentials' methods are called in the right order and - * the password array is filled with zeros after use. - */ - @Test - public void verifyAddUser() { - DB db = PowerMockito.mock(DB.class); - CountDownLatch latch = new CountDownLatch(1); - MongoStorage storage = new MongoStorage(db, latch); - - StorageCredentials creds = mock(StorageCredentials.class); - String username = "fooUser"; - char[] password = new char[] { 'f', 'o', 'o' }; - when(creds.getUsername()).thenReturn(username); - when(creds.getPassword()).thenReturn(password); - InOrder inOrder = inOrder(creds); - - AddUserCommand command = new AddUserCommand(null /* unused */); - command.addUser(storage, creds); - - // password should have been zero-filled - assertTrue(Arrays.equals(new char[] { '\0', '\0', '\0' }, password)); - // First username, then password should get called. - inOrder.verify(creds).getUsername(); - inOrder.verify(creds).getPassword(); - } - - /* - * Verifies if the delegate can be retrieved from QueuedStorage since - * AddUserCommand relies on this. In particular the delegate needs to be - * a MongoStorage instance. - */ - @Test - public void verifyGettingDelegateWorks() { - DB db = PowerMockito.mock(DB.class); - CountDownLatch latch = new CountDownLatch(1); - // Delegate must be mongostorage - MongoStorage storage = new MongoStorage(db, latch); - - QueuedStorage qStorage = new QueuedStorage(storage); - AddUserCommand command = new AddUserCommand(null /* unused */); - Storage actual = command.getDelegate(qStorage); - - assertSame(storage, actual); - } -}
--- a/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/BaseAddUserCommandTest.java Wed May 20 14:40:55 2015 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -/* - * Copyright 2012-2015 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.storage.mongodb.internal; - -import static org.junit.Assert.assertFalse; - -import org.junit.Test; - -import com.redhat.thermostat.common.cli.CommandContext; -import com.redhat.thermostat.common.cli.CommandException; - -public class BaseAddUserCommandTest { - - @Test - public void storageRequiredFalse() { - TestAddUserCommand cmd = new TestAddUserCommand(); - assertFalse(cmd.isStorageRequired()); - } - - private static class TestAddUserCommand extends BaseAddUserCommand { - - @Override - public void run(CommandContext ctx) throws CommandException { - // no-op - } - - } -}
--- a/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorageTest.java Wed May 20 14:40:55 2015 -0400 +++ b/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorageTest.java Thu May 21 15:36:44 2015 -0400 @@ -904,48 +904,6 @@ assertFalse(bool2.getValue()); } - /* - * AddUserCommand family use this API. Tests that working - * credentials don't get recreated, since this would fail - * anyway. - */ - @Test - public void verifyExistingUserIsNotAdded() throws Exception { - DB db = PowerMockito.mock(DB.class); - CountDownLatch latch = new CountDownLatch(1); - MongoStorage storage = new MongoStorage(db, latch); - - String username = "testUser"; - char password[] = new char[] { 'f', 'o', 'o' }; - when(db.authenticate(eq(username), eq(password))).thenReturn(true); - - // This should not have called db.addUser() - storage.addUser(username, password); - - verify(db, times(0)).addUser(any(String.class), any(char[].class)); - } - - /* - * AddUserCommand family use this API. Tests that working - * credentials don't get recreated, since this would fail - * anyway. - */ - @Test - public void verifyNotExistingUserAdded() throws Exception { - DB db = PowerMockito.mock(DB.class); - CountDownLatch latch = new CountDownLatch(1); - MongoStorage storage = new MongoStorage(db, latch); - - String username = "testUser"; - char password[] = new char[] { 'f', 'o', 'o' }; - when(db.authenticate(eq(username), eq(password))).thenReturn(false); - - // This should not have called db.addUser() - storage.addUser(username, password); - - verify(db).addUser(eq(username), eq(password)); - } - private static class FakeDataClass implements Pojo {}; }