Additional tests for DuplicateAdminRepair, remove old DupAdminRepair.
Project: http://git-wip-us.apache.org/repos/asf/usergrid/repo Commit: http://git-wip-us.apache.org/repos/asf/usergrid/commit/ceb81076 Tree: http://git-wip-us.apache.org/repos/asf/usergrid/tree/ceb81076 Diff: http://git-wip-us.apache.org/repos/asf/usergrid/diff/ceb81076 Branch: refs/heads/1.x Commit: ceb81076520db67e88f6c7a0e0934e39703309e7 Parents: e525f4f Author: Dave Johnson <[email protected]> Authored: Mon Jan 11 18:08:54 2016 -0500 Committer: Dave Johnson <[email protected]> Committed: Mon Jan 11 18:08:54 2016 -0500 ---------------------------------------------------------------------- .../apache/usergrid/tools/DupAdminRepair.java | 311 ------------------- .../usergrid/tools/DuplicateAdminRepair.java | 289 +++++++++++++++++ .../tools/DuplicateAdminUserRepair.java | 289 ----------------- .../tools/DuplicateAdminRepairTest.java | 301 ++++++++++++++++++ .../tools/DuplicateAdminUserRepairTest.java | 301 ------------------ .../usergrid/tools/MockUserOrgManager.java | 2 +- 6 files changed, 591 insertions(+), 902 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/usergrid/blob/ceb81076/stack/tools/src/main/java/org/apache/usergrid/tools/DupAdminRepair.java ---------------------------------------------------------------------- diff --git a/stack/tools/src/main/java/org/apache/usergrid/tools/DupAdminRepair.java b/stack/tools/src/main/java/org/apache/usergrid/tools/DupAdminRepair.java deleted file mode 100644 index 45929e8..0000000 --- a/stack/tools/src/main/java/org/apache/usergrid/tools/DupAdminRepair.java +++ /dev/null @@ -1,311 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.usergrid.tools; - - -import java.io.FileWriter; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.apache.usergrid.management.OrganizationInfo; -import org.apache.usergrid.management.UserInfo; -import org.apache.usergrid.persistence.Entity; -import org.apache.usergrid.persistence.EntityManager; -import org.apache.usergrid.persistence.Query; -import org.apache.usergrid.persistence.Results; -import org.apache.usergrid.persistence.SimpleEntityRef; -import org.apache.usergrid.persistence.cassandra.CassandraService; -import org.apache.usergrid.persistence.entities.Application; -import org.apache.usergrid.persistence.entities.User; -import org.apache.usergrid.persistence.exceptions.DuplicateUniquePropertyExistsException; -import org.apache.usergrid.utils.JsonUtils; - -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.Option; -import org.apache.commons.cli.OptionBuilder; -import org.apache.commons.cli.Options; - -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; - -import static org.apache.usergrid.persistence.cassandra.CassandraService.MANAGEMENT_APPLICATION_ID; - - -/** - * This is a utility to load all entities in an application and re-save them, this forces the secondary indexing to be - * updated. - * - * @author tnine - */ -public class DupAdminRepair extends ExportingToolBase { - - /** - * - */ - private static final int PAGE_SIZE = 100; - - private static final Logger logger = LoggerFactory.getLogger( DupAdminRepair.class ); - - - @Override - @SuppressWarnings("static-access") - public Options createOptions() { - - Option hostOption = - OptionBuilder.withArgName( "host" ).hasArg().isRequired( true ).withDescription( "Cassandra host" ) - .create( "host" ); - - Option outputOption = - OptionBuilder.withArgName( "output" ).hasArg().isRequired( true ).withDescription( "Cassandra host" ) - .create( "output" ); - - Options options = new Options(); - options.addOption( hostOption ); - options.addOption( outputOption ); - - return options; - } - - - /* - * (non-Javadoc) - * - * @see - * org.apache.usergrid.tools.ToolBase#runTool(org.apache.commons.cli.CommandLine) - */ - @Override - public void runTool( CommandLine line ) throws Exception { - String outputDir = line.getOptionValue( "output" ); - - String emailsDir = String.format( "%s/emails", outputDir ); - String usernamesDir = String.format( "%s/usernames", outputDir ); - createDir( emailsDir ); - createDir( usernamesDir ); - - startSpring(); - - logger.info( "Starting crawl of all admins" ); - - EntityManager em = emf.getEntityManager( CassandraService.MANAGEMENT_APPLICATION_ID ); - Application app = em.getApplication(); - - // search for all orgs - - Query query = new Query(); - query.setLimit( PAGE_SIZE ); - Results r = null; - - Multimap<String, UUID> emails = HashMultimap.create(); - Multimap<String, UUID> usernames = HashMultimap.create(); - do { - - r = em.searchCollection( app, "users", query ); - - for ( Entity entity : r.getEntities() ) { - emails.put( entity.getProperty( "email" ).toString().toLowerCase(), entity.getUuid() ); - usernames.put( entity.getProperty( "username" ).toString().toLowerCase(), entity.getUuid() ); - } - - query.setCursor( r.getCursor() ); - - logger.info( "Searching next page" ); - } - while ( r != null && r.size() == PAGE_SIZE ); - - // now go through and print out duplicate emails - - for ( String username : usernames.keySet() ) { - Collection<UUID> ids = usernames.get( username ); - - if ( ids.size() > 1 ) { - logger.info( "Found multiple users with the username {}", username ); - - // force the username to be reset to the user's email - resolveUsernameConflicts( usernamesDir, username, ids ); - } - } - - for ( String email : emails.keySet() ) { - Collection<UUID> ids = emails.get( email ); - - if ( ids.size() > 1 ) { - // get the admin the same way as the rest tier, this way the OTHER - // admins will be removed - UserInfo targetUser = managementService.getAdminUserByEmail( email ); - - if ( targetUser == null ) { - - List<UUID> tempIds = new ArrayList<UUID>( ids ); - Collections.sort( tempIds ); - - UUID toLoad = tempIds.get( 0 ); - - logger.warn( "Could not load target user by email {}, loading by UUID {} instead", email, toLoad ); - targetUser = managementService.getAdminUserByUuid( toLoad ); - - ids.remove( toLoad ); - } - - UUID targetId = targetUser.getUuid(); - - ids.remove( targetId ); - - logger.warn( "Found multiple admins with the email {}. Retaining uuid {}", email, targetId ); - - FileWriter file = new FileWriter( String.format( "%s/%s.all", emailsDir, email ) ); - - Map<String, Object> userOrganizationData = managementService.getAdminUserOrganizationData( targetId ); - - file.write( JsonUtils.mapToFormattedJsonString( userOrganizationData ) ); - - for ( UUID id : ids ) { - - userOrganizationData = managementService.getAdminUserOrganizationData( id ); - - file.write( JsonUtils.mapToFormattedJsonString( userOrganizationData ) ); - - file.write( "\n\n" ); - - mergeAdmins( emailsDir, id, targetId ); - } - - file.flush(); - file.close(); - - // force the index update after all other admins have been merged - logger.info( "Forcing re-index of admin with email {} and id {}", email, targetId ); - User targetUserEntity = em.get( targetUser.getUuid(), User.class ); - em.update( targetUserEntity ); - - FileWriter merged = new FileWriter( String.format( "%s/%s.merged", emailsDir, email ) ); - - userOrganizationData = managementService.getAdminUserOrganizationData( targetUser.getUuid() ); - - merged.write( JsonUtils.mapToFormattedJsonString( userOrganizationData ) ); - merged.flush(); - merged.close(); - } - } - - logger.info( "Repair complete" ); - } - - - /** - * When our usernames are equal, we need to check if our emails are equal. If they're not, we need to change the one - * that DOES NOT get returned on a lookup by username - */ - private void resolveUsernameConflicts( String targetDir, String userName, Collection<UUID> ids ) throws Exception { - // lookup the admin id - UserInfo existing = managementService.getAdminUserByUsername( userName ); - - if ( existing == null ) { - logger.warn( "Could not determine an admin for colliding username '{}'. Skipping", userName ); - return; - } - - ids.remove( existing.getUuid() ); - - boolean collision = false; - - EntityManager em = emf.getEntityManager( MANAGEMENT_APPLICATION_ID ); - - for ( UUID id : ids ) { - UserInfo other = managementService.getAdminUserByUuid( id ); - - // same username and email, these will be merged later in the process, - // skip it - if ( other != null && other.getEmail() != null && other.getEmail().equals( existing.getEmail() ) ) { - logger.info( - "Users with the same username '{}' have the same email '{}'. This will be resolved later in " - + "the process, skipping", userName, existing.getEmail() ); - continue; - } - - // if we get here, the emails do not match, but the usernames do. Force - // both usernames to emails - collision = true; - - setUserName( em, other, other.getEmail() ); - } - - if ( collision ) { - setUserName( em, existing, existing.getEmail() ); - } - } - - - /** Set the username to the one provided, if we can't due to duplicate property issues, we fall back to user+uuid */ - private void setUserName( EntityManager em, UserInfo other, String newUserName ) throws Exception { - logger.info( "Setting username to {} for user with username {} and id {}", new Object[] { - newUserName, other.getUsername(), other.getUuid() - } ); - - try { - em.setProperty( new SimpleEntityRef( "user", other.getUuid() ), "username", newUserName, true ); - } - catch ( DuplicateUniquePropertyExistsException e ) { - logger.warn( "More than 1 user has the username of {}. Setting the username to their username+UUID as a " - + "fallback", newUserName ); - - setUserName( em, other, String.format( "%s-%s", other.getUsername(), other.getUuid() ) ); - } - } - - - /** Merge the source admin to the target admin by copying oranizations. Then deletes the source admin */ - private void mergeAdmins( String targetDir, UUID sourceId, UUID targetId ) throws Exception { - - EntityManager em = emf.getEntityManager( MANAGEMENT_APPLICATION_ID ); - - User sourceUser = em.get( sourceId, User.class ); - - // may have already been deleted, do nothing - if ( sourceUser == null ) { - logger.warn( "Source admin with uuid {} does not exist in cassandra", sourceId ); - return; - } - - UserInfo targetUserInfo = managementService.getAdminUserByUuid( targetId ); - - @SuppressWarnings("unchecked") Map<String, Map<String, UUID>> sourceOrgs = - ( Map<String, Map<String, UUID>> ) managementService.getAdminUserOrganizationData( sourceId ) - .get( "organizations" ); - - for ( String orgName : sourceOrgs.keySet() ) { - UUID orgId = sourceOrgs.get( orgName ).get( "uuid" ); - - OrganizationInfo org = managementService.getOrganizationByUuid( orgId ); - - logger.info( "Adding organization {} to admin with email {} and id {}", - new Object[] { org.getName(), sourceUser.getEmail(), sourceUser.getUuid() } ); - - // copy it over to the target admin - managementService.addAdminUserToOrganization( targetUserInfo, org, false ); - } - - logger.info( "Deleting admin with email {} and id {}", sourceUser.getEmail(), sourceUser.getUuid() ); - - em.delete( sourceUser ); - } -} http://git-wip-us.apache.org/repos/asf/usergrid/blob/ceb81076/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateAdminRepair.java ---------------------------------------------------------------------- diff --git a/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateAdminRepair.java b/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateAdminRepair.java new file mode 100644 index 0000000..f38e3d6 --- /dev/null +++ b/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateAdminRepair.java @@ -0,0 +1,289 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.usergrid.tools; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.OptionBuilder; +import org.apache.commons.cli.Options; +import org.apache.commons.lang3.StringUtils; +import org.apache.usergrid.management.ManagementService; +import org.apache.usergrid.persistence.EntityManagerFactory; +import rx.functions.Action1; + +import java.util.*; + +import static org.apache.usergrid.tools.UserOrgInterface.Org; +import static org.apache.usergrid.tools.UserOrgInterface.OrgUser; + + +/** + * Find duplicate admin users, delete the one that is not indexed. + */ +public class DuplicateAdminRepair extends ToolBase { + + UserOrgInterface manager = null; + + static final String THREADS_ARG_NAME = "threads"; + + int threadCount = 5; + + static final String DRYRUN_ARG_NAME = "dryrun"; + + boolean dryRun = false; + + Multimap<String, OrgUser> emails = HashMultimap.create(); + + Multimap<String, OrgUser> usernames = HashMultimap.create(); + + boolean testing = false; + + + DuplicateAdminRepair() { + super(); + } + + DuplicateAdminRepair(EntityManagerFactory emf, ManagementService managementService ) { + this(); + this.emf = emf; + this.managementService = managementService; + } + + + @Override + @SuppressWarnings("static-access") + public Options createOptions() { + + Options options = super.createOptions(); + + Option dryRunOption = OptionBuilder.hasArg() + .withType(Boolean.TRUE) + .withDescription( "-" + DRYRUN_ARG_NAME + " true to print what tool would do and do not alter data.") + .create( DRYRUN_ARG_NAME ); + options.addOption( dryRunOption ); + + Option writeThreadsOption = OptionBuilder.hasArg() + .withType(0) + .withDescription( "Write Threads -" + THREADS_ARG_NAME ) + .create(THREADS_ARG_NAME); + options.addOption( writeThreadsOption ); + + return options; + } + + + public UserOrgManager createNewRepairManager() { + return new UserOrgManager( emf, managementService ); + } + + + @Override + public void runTool(CommandLine line) throws Exception { + + startSpring(); + setVerbose( line ); + + if (StringUtils.isNotEmpty( line.getOptionValue( THREADS_ARG_NAME ) )) { + try { + threadCount = Integer.parseInt( line.getOptionValue( THREADS_ARG_NAME ) ); + } catch (NumberFormatException nfe) { + logger.error( "-" + THREADS_ARG_NAME + " must be specified as an integer. Aborting..." ); + return; + } + } + + if ( StringUtils.isNotEmpty( line.getOptionValue( DRYRUN_ARG_NAME ) )) { + dryRun = Boolean.parseBoolean( line.getOptionValue( DRYRUN_ARG_NAME )); + } + + if ( manager == null ) { // we use a special manager when mockTesting + if (dryRun) { + manager = new DryRunUserOrgManager( emf, managementService ); + } else { + manager = new UserOrgManager( emf, managementService ); + } + } + + logger.info( "DuplicateAdminUserRepair tool starting up... manager: " + manager.getClass().getSimpleName() ); + + // build multi-map of users by email and users by name + + manager.getUsers().doOnNext( new Action1<OrgUser>() { + @Override + public void call( OrgUser user ) { + + if (user.getUsername() == null) { + logger.warn( "User {} has no username", user.getId() ); + return; + } + if (user.getEmail() == null) { + logger.warn( "User {} has no email", user.getId() ); + return; + } + emails.put( user.getEmail(), user ); + usernames.put( user.getEmail(), user ); + + } + } ).toBlocking().lastOrDefault( null ); + + for ( String username : usernames.keySet() ) { + Collection<OrgUser> users = usernames.get( username ); + + if ( users.size() > 1 ) { + logger.info( "Found multiple users with the username {}", username ); + + // force the username to be reset to the user's email + resolveUsernameConflicts( username, users ); + } + } + + for ( String email : emails.keySet() ) { + + Collection<OrgUser> users = emails.get( email ); + + if ( users.size() > 1 ) { + // get the admin the same way as the rest tier, this way the OTHER + // admins will be removed + OrgUser targetUser = manager.lookupOrgUserByEmail( email ); + + if ( targetUser == null ) { + + List<OrgUser> tempUsers = new ArrayList<OrgUser>( users ); + Collections.sort( tempUsers ); + + OrgUser toLoad = tempUsers.get( 0 ); + + logger.warn( "Could not load target user by email {}, loading by UUID {} instead", email, toLoad ); + targetUser = toLoad; + + users.remove( toLoad ); + } + + users.remove( targetUser ); + + logger.warn( "Found multiple admins with the email {}. Retaining uuid {}", email, targetUser.getId() ); + + for ( OrgUser orgUser : users ) { + mergeAdmins( orgUser, targetUser ); + } + + // force the index update after all other admins have been merged + if ( dryRun ) { + logger.info("Would force re-index of 'keeper' user {}:{}", + targetUser.getUsername(), targetUser.getId()); + } else { + logger.info( "Forcing re-index of admin with email {} and id {}", email, targetUser.getId()); + manager.updateOrgUser( targetUser ); + } + } + } + + logger.info( "Repair complete" ); + } + + + /** + * When our usernames are equal, we need to check if our emails are equal. If they're not, we need to change the one + * that DOES NOT get returned on a lookup by username + */ + private void resolveUsernameConflicts( String userName, Collection<OrgUser> users ) throws Exception { + + // lookup the admin id + OrgUser existing = manager.lookupOrgUserByUsername( userName ); + + if ( existing == null ) { + logger.warn( "Could not determine an admin for colliding username '{}'. Skipping", userName ); + return; + } + + users.remove( existing ); + + boolean collision = false; + + for ( OrgUser other : users ) { + + // same username and email, these will be merged later in the process, + // skip it + if ( other != null && other.getEmail() != null && other.getEmail().equals( existing.getEmail() ) ) { + logger.info( + "Users with the same username '{}' have the same email '{}'. This will be resolved later in " + + "the process, skipping", userName, existing.getEmail() ); + continue; + } + + // if we get here, the emails do not match, but the usernames do. Force + // both usernames to emails + collision = true; + + setUserName(other, other.getEmail() ); + } + + if ( collision ) { + setUserName(existing, existing.getEmail() ); + } + } + + + /** Set the username to the one provided, if we can't due to duplicate property issues, we fall back to user+uuid */ + private void setUserName( OrgUser other, String newUserName ) throws Exception { + + if ( dryRun ) { + logger.info("Would rename user {}:{} to {}", new Object[] { + other.getUsername(), other.getId(), newUserName }); + } else { + logger.info( "Setting username to {} for user {}:{}", new Object[] { + newUserName, other.getUsername(), other.getId() } ); + + manager.setOrgUserName( other, newUserName ); + } + } + + + /** Merge the source admin to the target admin by copying oranizations. Then deletes the source admin */ + private void mergeAdmins( OrgUser sourceUser, OrgUser targetUser ) throws Exception { + + Set<Org> sourceOrgs = manager.getUsersOrgs( sourceUser ); + + for ( Org org : sourceOrgs ) { + + if ( dryRun ) { + logger.info("Would add org {}:{} to user {}:{}", new Object[] { + org.getName(), org.getId(), targetUser.getUsername(), targetUser.getId(), }); + + } else { + logger.info( "Adding organization {}:{} to admin with email {} and id {}", + new Object[] { org.getName(), org.getId(), targetUser.getEmail(), targetUser.getId() } ); + + // copy it over to the target admin + manager.addUserToOrg( targetUser, org ); + } + } + + logger.info( "Deleting admin with email {} and id {}", sourceUser.getEmail(), sourceUser.getId() ); + + if ( dryRun ) { + logger.info( "Would remove user {}:{}", new Object[]{ + sourceUser.getUsername(), sourceUser.getId() } ); + + } else { + manager.removeOrgUser( sourceUser ); + } + } + +} http://git-wip-us.apache.org/repos/asf/usergrid/blob/ceb81076/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateAdminUserRepair.java ---------------------------------------------------------------------- diff --git a/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateAdminUserRepair.java b/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateAdminUserRepair.java deleted file mode 100644 index 902eefa..0000000 --- a/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateAdminUserRepair.java +++ /dev/null @@ -1,289 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.usergrid.tools; - -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.Option; -import org.apache.commons.cli.OptionBuilder; -import org.apache.commons.cli.Options; -import org.apache.commons.lang3.StringUtils; -import org.apache.usergrid.management.ManagementService; -import org.apache.usergrid.persistence.EntityManagerFactory; -import rx.functions.Action1; - -import java.util.*; - -import static org.apache.usergrid.tools.UserOrgInterface.Org; -import static org.apache.usergrid.tools.UserOrgInterface.OrgUser; - - -/** - * Find duplicate admin users, delete the one that is not indexed. - */ -public class DuplicateAdminUserRepair extends ToolBase { - - UserOrgInterface manager = null; - - static final String THREADS_ARG_NAME = "threads"; - - int threadCount = 5; - - static final String DRYRUN_ARG_NAME = "dryrun"; - - boolean dryRun = false; - - Multimap<String, OrgUser> emails = HashMultimap.create(); - - Multimap<String, OrgUser> usernames = HashMultimap.create(); - - boolean testing = false; - - - DuplicateAdminUserRepair() { - super(); - } - - DuplicateAdminUserRepair(EntityManagerFactory emf, ManagementService managementService ) { - this(); - this.emf = emf; - this.managementService = managementService; - } - - - @Override - @SuppressWarnings("static-access") - public Options createOptions() { - - Options options = super.createOptions(); - - Option dryRunOption = OptionBuilder.hasArg() - .withType(Boolean.TRUE) - .withDescription( "-" + DRYRUN_ARG_NAME + " true to print what tool would do and do not alter data.") - .create( DRYRUN_ARG_NAME ); - options.addOption( dryRunOption ); - - Option writeThreadsOption = OptionBuilder.hasArg() - .withType(0) - .withDescription( "Write Threads -" + THREADS_ARG_NAME ) - .create(THREADS_ARG_NAME); - options.addOption( writeThreadsOption ); - - return options; - } - - - public UserOrgManager createNewRepairManager() { - return new UserOrgManager( emf, managementService ); - } - - - @Override - public void runTool(CommandLine line) throws Exception { - - startSpring(); - setVerbose( line ); - - if (StringUtils.isNotEmpty( line.getOptionValue( THREADS_ARG_NAME ) )) { - try { - threadCount = Integer.parseInt( line.getOptionValue( THREADS_ARG_NAME ) ); - } catch (NumberFormatException nfe) { - logger.error( "-" + THREADS_ARG_NAME + " must be specified as an integer. Aborting..." ); - return; - } - } - - if ( StringUtils.isNotEmpty( line.getOptionValue( DRYRUN_ARG_NAME ) )) { - dryRun = Boolean.parseBoolean( line.getOptionValue( DRYRUN_ARG_NAME )); - } - - if ( manager == null ) { // we use a special manager when mockTesting - if (dryRun) { - manager = new DryRunUserOrgManager( emf, managementService ); - } else { - manager = new UserOrgManager( emf, managementService ); - } - } - - logger.info( "DuplicateAdminUserRepair tool starting up... manager: " + manager.getClass().getSimpleName() ); - - // build multi-map of users by email and users by name - - manager.getUsers().doOnNext( new Action1<OrgUser>() { - @Override - public void call( OrgUser user ) { - - if (user.getUsername() == null) { - logger.warn( "User {} has no username", user.getId() ); - return; - } - if (user.getEmail() == null) { - logger.warn( "User {} has no email", user.getId() ); - return; - } - emails.put( user.getEmail(), user ); - usernames.put( user.getEmail(), user ); - - } - } ).toBlocking().lastOrDefault( null ); - - for ( String username : usernames.keySet() ) { - Collection<OrgUser> users = usernames.get( username ); - - if ( users.size() > 1 ) { - logger.info( "Found multiple users with the username {}", username ); - - // force the username to be reset to the user's email - resolveUsernameConflicts( username, users ); - } - } - - for ( String email : emails.keySet() ) { - - Collection<OrgUser> users = emails.get( email ); - - if ( users.size() > 1 ) { - // get the admin the same way as the rest tier, this way the OTHER - // admins will be removed - OrgUser targetUser = manager.lookupOrgUserByEmail( email ); - - if ( targetUser == null ) { - - List<OrgUser> tempUsers = new ArrayList<OrgUser>( users ); - Collections.sort( tempUsers ); - - OrgUser toLoad = tempUsers.get( 0 ); - - logger.warn( "Could not load target user by email {}, loading by UUID {} instead", email, toLoad ); - targetUser = toLoad; - - users.remove( toLoad ); - } - - users.remove( targetUser ); - - logger.warn( "Found multiple admins with the email {}. Retaining uuid {}", email, targetUser.getId() ); - - for ( OrgUser orgUser : users ) { - mergeAdmins( orgUser, targetUser ); - } - - // force the index update after all other admins have been merged - if ( dryRun ) { - logger.info("Would force re-index of 'keeper' user {}:{}", - targetUser.getUsername(), targetUser.getId()); - } else { - logger.info( "Forcing re-index of admin with email {} and id {}", email, targetUser.getId()); - manager.updateOrgUser( targetUser ); - } - } - } - - logger.info( "Repair complete" ); - } - - - /** - * When our usernames are equal, we need to check if our emails are equal. If they're not, we need to change the one - * that DOES NOT get returned on a lookup by username - */ - private void resolveUsernameConflicts( String userName, Collection<OrgUser> users ) throws Exception { - - // lookup the admin id - OrgUser existing = manager.lookupOrgUserByUsername( userName ); - - if ( existing == null ) { - logger.warn( "Could not determine an admin for colliding username '{}'. Skipping", userName ); - return; - } - - users.remove( existing ); - - boolean collision = false; - - for ( OrgUser other : users ) { - - // same username and email, these will be merged later in the process, - // skip it - if ( other != null && other.getEmail() != null && other.getEmail().equals( existing.getEmail() ) ) { - logger.info( - "Users with the same username '{}' have the same email '{}'. This will be resolved later in " - + "the process, skipping", userName, existing.getEmail() ); - continue; - } - - // if we get here, the emails do not match, but the usernames do. Force - // both usernames to emails - collision = true; - - setUserName(other, other.getEmail() ); - } - - if ( collision ) { - setUserName(existing, existing.getEmail() ); - } - } - - - /** Set the username to the one provided, if we can't due to duplicate property issues, we fall back to user+uuid */ - private void setUserName( OrgUser other, String newUserName ) throws Exception { - - if ( dryRun ) { - logger.info("Would rename user {}:{} to {}", new Object[] { - other.getUsername(), other.getId(), newUserName }); - } else { - logger.info( "Setting username to {} for user with username {} and id {}", new Object[] { - newUserName, other.getUsername(), other.getId() } ); - - manager.setOrgUserName( other, newUserName ); - } - } - - - /** Merge the source admin to the target admin by copying oranizations. Then deletes the source admin */ - private void mergeAdmins( OrgUser sourceUser, OrgUser targetUser ) throws Exception { - - Set<Org> sourceOrgs = manager.getUsersOrgs( sourceUser ); - - for ( Org org : sourceOrgs ) { - - if ( dryRun ) { - logger.info("Would add org {}:{} to user {}:{}", new Object[] { - org.getName(), org.getId(), targetUser.getUsername(), targetUser.getId(), }); - - } else { - logger.info( "Adding organization {}:{} to admin with email {} and id {}", - new Object[] { org.getName(), org.getId(), targetUser.getEmail(), targetUser.getId() } ); - - // copy it over to the target admin - manager.addUserToOrg( targetUser, org ); - } - } - - logger.info( "Deleting admin with email {} and id {}", sourceUser.getEmail(), sourceUser.getId() ); - - if ( dryRun ) { - logger.info( "Would remove user {}:{}", new Object[]{ - sourceUser.getUsername(), sourceUser.getId() } ); - - } else { - manager.removeOrgUser( sourceUser ); - } - } - -} http://git-wip-us.apache.org/repos/asf/usergrid/blob/ceb81076/stack/tools/src/test/java/org/apache/usergrid/tools/DuplicateAdminRepairTest.java ---------------------------------------------------------------------- diff --git a/stack/tools/src/test/java/org/apache/usergrid/tools/DuplicateAdminRepairTest.java b/stack/tools/src/test/java/org/apache/usergrid/tools/DuplicateAdminRepairTest.java new file mode 100644 index 0000000..e5e9d43 --- /dev/null +++ b/stack/tools/src/test/java/org/apache/usergrid/tools/DuplicateAdminRepairTest.java @@ -0,0 +1,301 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.usergrid.tools; + + +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.usergrid.ServiceITSetup; +import org.apache.usergrid.ServiceITSetupImpl; +import org.apache.usergrid.ServiceITSuite; +import org.apache.usergrid.management.OrganizationOwnerInfo; +import org.apache.usergrid.management.UserInfo; +import org.junit.ClassRule; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.UUID; + +import static junit.framework.Assert.assertNull; +import static junit.framework.Assert.assertTrue; +import static junit.framework.TestCase.assertNotNull; +import static org.apache.usergrid.tools.UserOrgInterface.OrgUser; +import static org.junit.Assert.assertEquals; + + +/** + * Test duplicate admin repair. + */ +public class DuplicateAdminRepairTest { + + static final Logger logger = LoggerFactory.getLogger( DuplicateAdminRepairTest.class ); + + @ClassRule + public static ServiceITSetup setup = new ServiceITSetupImpl( ServiceITSuite.cassandraResource ); + + + /** + * Test tool logic with mock manager that returns duplicates + */ + @org.junit.Test + public void testMockWithDups() throws Exception { + + DuplicateAdminRepair dor = new DuplicateAdminRepair(); + MockManager mockManager = new MockManager(); + dor.manager = mockManager; + dor.testing = true; + + // the MockManager creates 2 pairs of duplicate orgs + assertNotNull( "user1_a", mockManager.getOrgUser( mockManager.user1_a.getId() )); + assertNotNull( "user1_b", mockManager.getOrgUser( mockManager.user1_b.getId() )); + assertNotNull( "user2_a", mockManager.getOrgUser( mockManager.user2_a.getId() )); + assertNotNull( "user2_b", mockManager.getOrgUser( mockManager.user2_b.getId() )); + + // verify that correct users indexed + assertUsersIndexed( mockManager ); + + dor.startTool( new String[] {}, false ); // false means do not call System.exit() + + // verify that correct users indexed + assertUsersIndexed( mockManager ); + + // verify that duplicate users are gone (the "a" users were the first ones created) + assertNull( "must remove user1_a", mockManager.getOrgUser( mockManager.user1_a.getId() )); + assertNull( "must remove user2_a", mockManager.getOrgUser( mockManager.user2_a.getId() )); + + // and keepers survived + assertNotNull( "user1_b survived", mockManager.getOrgUser( mockManager.user1_b.getId() )); + assertNotNull( "user2_b survived", mockManager.getOrgUser( mockManager.user2_b.getId() )); + } + + + private void assertUsersIndexed(MockManager mockManager ) { + assertEquals("user1_b is in the index", + mockManager.lookupOrgUserByUsername(mockManager.user1_b.getUsername()).getId(), + mockManager.user1_b.getId() ); + + assertEquals("user1_b is in the index", + mockManager.lookupOrgUserByEmail(mockManager.user1_b.getEmail()).getId(), + mockManager.user1_b.getId() ); + + assertEquals("user2_b is in the index", + mockManager.lookupOrgUserByUsername(mockManager.user2_b.getUsername()).getId(), + mockManager.user2_b.getId() ); + + assertEquals("user2_b is in the index", + mockManager.lookupOrgUserByEmail(mockManager.user2_b.getEmail()).getId(), + mockManager.user2_b.getId() ); + } + + + @org.junit.Test + public void testDryRun() throws Exception { + + DuplicateAdminRepair dor = new DuplicateAdminRepair(); + MockManager mockManager = new MockManager(); + dor.manager = mockManager; + dor.testing = true; + + // the MockManager creates 2 pairs of duplicate orgs + assertNotNull( "user1_a", mockManager.getOrgUser( mockManager.user1_a.getId() )); + assertNotNull( "user1_b", mockManager.getOrgUser( mockManager.user1_b.getId() )); + assertNotNull( "user2_a", mockManager.getOrgUser( mockManager.user2_a.getId() )); + assertNotNull( "user2_b", mockManager.getOrgUser( mockManager.user2_b.getId() )); + + // verify that correct users indexed + assertUsersIndexed( mockManager ); + + dor.startTool( new String[] { "-dryrun", "true" }, false ); // false means do not call System.exit() + + // verify that correct users indexed + assertUsersIndexed( mockManager ); + + // insure nothng was deleted by dry-run + assertNotNull( "dryrun should not delete user1_a", mockManager.getOrgUser( mockManager.user1_a.getId() )); + assertNotNull( "dryrun should not delete user1_b", mockManager.getOrgUser( mockManager.user1_b.getId() )); + assertNotNull( "dryrun should not delete user2_a", mockManager.getOrgUser( mockManager.user2_a.getId() )); + assertNotNull( "dryrun should not delete user2_b", mockManager.getOrgUser( mockManager.user2_b.getId() )); + } + + + /** + * Smoke test: does "real" manager run without throwing exceptions? + */ + @org.junit.Test + public void testManagerNoDups() throws Exception { + + // create two orgs each with owning user + + final String random1 = org.apache.commons.lang.RandomStringUtils.randomAlphanumeric( 10 ); + final OrganizationOwnerInfo orgOwnerInfo1 = setup.getMgmtSvc().createOwnerAndOrganization( + "org_" + random1, "user_" + random1, "user_" + random1, + "user_" + random1 + "@example.com", "password" ); + + final String random2 = org.apache.commons.lang.RandomStringUtils.randomAlphanumeric( 10 ); + final OrganizationOwnerInfo orgOwnerInfo2 = setup.getMgmtSvc().createOwnerAndOrganization( + "org_" + random2, "user_" + random2, "user_" + random2, + "user_" + random2 + "@example.com", "password" ); + + // Add user1 to org2 + + setup.getMgmtSvc().addAdminUserToOrganization( + orgOwnerInfo1.getOwner(), orgOwnerInfo2.getOrganization(), false ); + + DuplicateAdminRepair dor = new DuplicateAdminRepair(); + + dor.startTool( new String[]{}, false ); // false means do not call System.exit() + + assertTrue( true ); // we're happy if we get to this point + } + + + @org.junit.Test + public void testManagerLookupMethods() throws Exception { + + // create two orgs each with owning user + + final String random1 = org.apache.commons.lang.RandomStringUtils.randomAlphanumeric( 10 ); + final OrganizationOwnerInfo orgOwnerInfo1 = setup.getMgmtSvc().createOwnerAndOrganization( + "org_" + random1, "user_" + random1, "user_" + random1, + "user_" + random1 + "@example.com", "password" ); + + final String random2 = org.apache.commons.lang.RandomStringUtils.randomAlphanumeric( 10 ); + final OrganizationOwnerInfo orgOwnerInfo2 = setup.getMgmtSvc().createOwnerAndOrganization( + "org_" + random2, "user_" + random2, "user_" + random2, + "user_" + random2 + "@example.com", "password" ); + + DuplicateAdminRepair dor = new DuplicateAdminRepair(setup.getEmf(), setup.getMgmtSvc()); + dor.manager = dor.createNewRepairManager(); // test the real manager + + // start the tool so that Spring, Cassandra, etc/ gets initialized + dor.startTool( new String[]{"-dryrun", "true"}, false ); // false means do not call System.exit() + + testManagerLookupMethods( dor, orgOwnerInfo1, orgOwnerInfo2, true ); + + dor.manager.removeOrgUser( dor.manager.getOrgUser( orgOwnerInfo1.getOwner().getUuid() )); + dor.manager.removeOrgUser( dor.manager.getOrgUser( orgOwnerInfo2.getOwner().getUuid() )); + + testManagerLookupMethods( dor, orgOwnerInfo1, orgOwnerInfo2, false ); + } + + + private void testManagerLookupMethods( DuplicateAdminRepair dor, + OrganizationOwnerInfo info1, + OrganizationOwnerInfo info2, + boolean usersExist ) throws Exception { + if ( usersExist ) { + + assertNotNull( dor.manager.getOrgUser( info1.getOwner().getUuid() )); + assertNotNull( dor.manager.getOrgUser( info2.getOwner().getUuid() )); + + assertNotNull( dor.manager.lookupOrgUserByEmail( info1.getOwner().getEmail() )); + assertNotNull( dor.manager.lookupOrgUserByEmail( info2.getOwner().getEmail() )); + + assertNotNull( dor.manager.lookupOrgUserByUsername( info1.getOwner().getUsername() )); + assertNotNull( dor.manager.lookupOrgUserByUsername( info2.getOwner().getUsername() )); + + } else { + + assertNull( dor.manager.getOrgUser( info1.getOwner().getUuid() ) ); + assertNull( dor.manager.getOrgUser( info2.getOwner().getUuid() ) ); + + assertNull( dor.manager.lookupOrgUserByEmail( info1.getOwner().getEmail() ) ); + assertNull( dor.manager.lookupOrgUserByEmail( info2.getOwner().getEmail() ) ); + + assertNull( dor.manager.lookupOrgUserByUsername( info1.getOwner().getUsername() ) ); + assertNull( dor.manager.lookupOrgUserByUsername( info2.getOwner().getUsername() ) ); + } + } + + + @org.junit.Test + public void testManagerOrgUserUpdateMethod() throws Exception { + + // create an org with an admin user + final String random1 = org.apache.commons.lang.RandomStringUtils.randomAlphanumeric( 10 ); + final OrganizationOwnerInfo orgOwnerInfo1 = setup.getMgmtSvc().createOwnerAndOrganization( + "org_" + random1, "user_" + random1, "user_" + random1, + "user_" + random1 + "@example.com", "password" ); + + DuplicateAdminRepair dor = new DuplicateAdminRepair(setup.getEmf(), setup.getMgmtSvc()); + dor.manager = dor.createNewRepairManager(); // test the real manager + + // start the tool so that Spring, Cassandra, etc/ gets initialized + dor.startTool( new String[]{"-dryrun", "true"}, false ); // false means do not call System.exit() + + UserInfo userInfo = setup.getMgmtSvc().getAdminUserByUuid( orgOwnerInfo1.getOwner().getUuid() ); + OrgUser user = dor.manager.getOrgUser( orgOwnerInfo1.getOwner().getUuid() ); + assertEquals( userInfo.getUsername(), user.getUsername()); + assertEquals( userInfo.getEmail(), user.getEmail()); + + // change user's username using updateOrgUser() + String newUsername = "boom_" + random1; + user.setUsername(newUsername); + dor.manager.updateOrgUser( user ); + user = dor.manager.getOrgUser( orgOwnerInfo1.getOwner().getUuid() ); + assertEquals( newUsername, user.getUsername()); + + // change user's username using setOrgUserName() + newUsername = "blammo_" + random1; + dor.manager.setOrgUserName( user, newUsername ); + user = dor.manager.getOrgUser( orgOwnerInfo1.getOwner().getUuid() ); + assertEquals( newUsername, user.getUsername()); + } + + + /** + * Extend mock manager to add a pair of duplicate users. + */ + static class MockManager extends MockUserOrgManager { + + OrgUser user1_a; + OrgUser user1_b; + OrgUser user2_a; + OrgUser user2_b; + + public MockManager() throws Exception { + + super(1); // ask parent to create one pair of duplicate orgs + + Org org = orgsById.values().iterator().next(); + + String sfx = RandomStringUtils.randomAlphanumeric(10); + + // user1 a and b have duplicate usernames AND DUPLICATE EMAIL ADDRESSES + + user1_a = createOrgUser( UUID.randomUUID(), "UserName_"+sfx, "UserName_"+sfx+"@example.com" ); + addUserToOrg( user1_a, org ); + pause(100); + + user1_b = createOrgUser( UUID.randomUUID(), "Username_"+sfx, "Username_"+sfx+"@example.com" ); + addUserToOrg( user1_b, org ); + pause(100); + + // user2 a and b have duplicate usernames AND DIFFERENT EMAIL ADDRESSES + + user2_a = createOrgUser( UUID.randomUUID(), "UserName_"+sfx, "UserName_"+sfx+"@example.com" ); + addUserToOrg( user2_a, org ); + pause(100); + + user2_b = createOrgUser( UUID.randomUUID(), "UserName_"+sfx, "UserName_"+sfx+"@example.com" ); + addUserToOrg( user2_b, org ); + pause(100); + + } + + } + +} http://git-wip-us.apache.org/repos/asf/usergrid/blob/ceb81076/stack/tools/src/test/java/org/apache/usergrid/tools/DuplicateAdminUserRepairTest.java ---------------------------------------------------------------------- diff --git a/stack/tools/src/test/java/org/apache/usergrid/tools/DuplicateAdminUserRepairTest.java b/stack/tools/src/test/java/org/apache/usergrid/tools/DuplicateAdminUserRepairTest.java deleted file mode 100644 index 6676b87..0000000 --- a/stack/tools/src/test/java/org/apache/usergrid/tools/DuplicateAdminUserRepairTest.java +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.usergrid.tools; - - -import org.apache.commons.lang3.RandomStringUtils; -import org.apache.usergrid.ServiceITSetup; -import org.apache.usergrid.ServiceITSetupImpl; -import org.apache.usergrid.ServiceITSuite; -import org.apache.usergrid.management.OrganizationOwnerInfo; -import org.apache.usergrid.management.UserInfo; -import org.junit.ClassRule; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.UUID; - -import static junit.framework.Assert.assertNull; -import static junit.framework.Assert.assertTrue; -import static junit.framework.TestCase.assertNotNull; -import static org.apache.usergrid.tools.UserOrgInterface.OrgUser; -import static org.junit.Assert.assertEquals; - - -/** - * Test duplicate admin repair. - */ -public class DuplicateAdminUserRepairTest { - - static final Logger logger = LoggerFactory.getLogger( DuplicateAdminUserRepairTest.class ); - - @ClassRule - public static ServiceITSetup setup = new ServiceITSetupImpl( ServiceITSuite.cassandraResource ); - - - /** - * Test tool logic with mock manager that returns duplicates - */ - @org.junit.Test - public void testMockWithDups() throws Exception { - - DuplicateAdminUserRepair dor = new DuplicateAdminUserRepair(); - MockManager mockManager = new MockManager(); - dor.manager = mockManager; - dor.testing = true; - - // the MockManager creates 2 pairs of duplicate orgs - assertNotNull( "user1_a", mockManager.getOrgUser( mockManager.user1_a.getId() )); - assertNotNull( "user1_b", mockManager.getOrgUser( mockManager.user1_b.getId() )); - assertNotNull( "user2_a", mockManager.getOrgUser( mockManager.user2_a.getId() )); - assertNotNull( "user2_b", mockManager.getOrgUser( mockManager.user2_b.getId() )); - - // verify that correct users indexed - assertUsersIndexed( mockManager ); - - dor.startTool( new String[] {}, false ); // false means do not call System.exit() - - // verify that correct users indexed - assertUsersIndexed( mockManager ); - - // verify that duplicate users are gone (the "a" users were the first ones created) - assertNull( "must remove user1_a", mockManager.getOrgUser( mockManager.user1_a.getId() )); - assertNull( "must remove user2_a", mockManager.getOrgUser( mockManager.user2_a.getId() )); - - // and keepers survived - assertNotNull( "user1_b survived", mockManager.getOrgUser( mockManager.user1_b.getId() )); - assertNotNull( "user2_b survived", mockManager.getOrgUser( mockManager.user2_b.getId() )); - } - - - private void assertUsersIndexed(MockManager mockManager ) { - assertEquals("user1_b is in the index", - mockManager.lookupOrgUserByUsername(mockManager.user1_b.getUsername()).getId(), - mockManager.user1_b.getId() ); - - assertEquals("user1_b is in the index", - mockManager.lookupOrgUserByEmail(mockManager.user1_b.getEmail()).getId(), - mockManager.user1_b.getId() ); - - assertEquals("user2_b is in the index", - mockManager.lookupOrgUserByUsername(mockManager.user2_b.getUsername()).getId(), - mockManager.user2_b.getId() ); - - assertEquals("user2_b is in the index", - mockManager.lookupOrgUserByEmail(mockManager.user2_b.getEmail()).getId(), - mockManager.user2_b.getId() ); - } - - - @org.junit.Test - public void testDryRun() throws Exception { - - DuplicateAdminUserRepair dor = new DuplicateAdminUserRepair(); - MockManager mockManager = new MockManager(); - dor.manager = mockManager; - dor.testing = true; - - // the MockManager creates 2 pairs of duplicate orgs - assertNotNull( "user1_a", mockManager.getOrgUser( mockManager.user1_a.getId() )); - assertNotNull( "user1_b", mockManager.getOrgUser( mockManager.user1_b.getId() )); - assertNotNull( "user2_a", mockManager.getOrgUser( mockManager.user2_a.getId() )); - assertNotNull( "user2_b", mockManager.getOrgUser( mockManager.user2_b.getId() )); - - // verify that correct users indexed - assertUsersIndexed( mockManager ); - - dor.startTool( new String[] { "-dryrun", "true" }, false ); // false means do not call System.exit() - - // verify that correct users indexed - assertUsersIndexed( mockManager ); - - // insure nothng was deleted by dry-run - assertNotNull( "dryrun should not delete user1_a", mockManager.getOrgUser( mockManager.user1_a.getId() )); - assertNotNull( "dryrun should not delete user1_b", mockManager.getOrgUser( mockManager.user1_b.getId() )); - assertNotNull( "dryrun should not delete user2_a", mockManager.getOrgUser( mockManager.user2_a.getId() )); - assertNotNull( "dryrun should not delete user2_b", mockManager.getOrgUser( mockManager.user2_b.getId() )); - } - - - /** - * Smoke test: does "real" manager run without throwing exceptions? - */ - @org.junit.Test - public void testManagerNoDups() throws Exception { - - // create two orgs each with owning user - - final String random1 = org.apache.commons.lang.RandomStringUtils.randomAlphanumeric( 10 ); - final OrganizationOwnerInfo orgOwnerInfo1 = setup.getMgmtSvc().createOwnerAndOrganization( - "org_" + random1, "user_" + random1, "user_" + random1, - "user_" + random1 + "@example.com", "password" ); - - final String random2 = org.apache.commons.lang.RandomStringUtils.randomAlphanumeric( 10 ); - final OrganizationOwnerInfo orgOwnerInfo2 = setup.getMgmtSvc().createOwnerAndOrganization( - "org_" + random2, "user_" + random2, "user_" + random2, - "user_" + random2 + "@example.com", "password" ); - - // Add user1 to org2 - - setup.getMgmtSvc().addAdminUserToOrganization( - orgOwnerInfo1.getOwner(), orgOwnerInfo2.getOrganization(), false ); - - DuplicateAdminUserRepair dor = new DuplicateAdminUserRepair(); - - dor.startTool( new String[]{}, false ); // false means do not call System.exit() - - assertTrue( true ); // we're happy if we get to this point - } - - - @org.junit.Test - public void testManagerLookupMethods() throws Exception { - - // create two orgs each with owning user - - final String random1 = org.apache.commons.lang.RandomStringUtils.randomAlphanumeric( 10 ); - final OrganizationOwnerInfo orgOwnerInfo1 = setup.getMgmtSvc().createOwnerAndOrganization( - "org_" + random1, "user_" + random1, "user_" + random1, - "user_" + random1 + "@example.com", "password" ); - - final String random2 = org.apache.commons.lang.RandomStringUtils.randomAlphanumeric( 10 ); - final OrganizationOwnerInfo orgOwnerInfo2 = setup.getMgmtSvc().createOwnerAndOrganization( - "org_" + random2, "user_" + random2, "user_" + random2, - "user_" + random2 + "@example.com", "password" ); - - DuplicateAdminUserRepair dor = new DuplicateAdminUserRepair(setup.getEmf(), setup.getMgmtSvc()); - dor.manager = dor.createNewRepairManager(); // test the real manager - - // start the tool so that Spring, Cassandra, etc/ gets initialized - dor.startTool( new String[]{"-dryrun", "true"}, false ); // false means do not call System.exit() - - testManagerLookupMethods( dor, orgOwnerInfo1, orgOwnerInfo2, true ); - - dor.manager.removeOrgUser( dor.manager.getOrgUser( orgOwnerInfo1.getOwner().getUuid() )); - dor.manager.removeOrgUser( dor.manager.getOrgUser( orgOwnerInfo2.getOwner().getUuid() )); - - testManagerLookupMethods( dor, orgOwnerInfo1, orgOwnerInfo2, false ); - } - - - private void testManagerLookupMethods( DuplicateAdminUserRepair dor, - OrganizationOwnerInfo info1, - OrganizationOwnerInfo info2, - boolean usersExist ) throws Exception { - if ( usersExist ) { - - assertNotNull( dor.manager.getOrgUser( info1.getOwner().getUuid() )); - assertNotNull( dor.manager.getOrgUser( info2.getOwner().getUuid() )); - - assertNotNull( dor.manager.lookupOrgUserByEmail( info1.getOwner().getEmail() )); - assertNotNull( dor.manager.lookupOrgUserByEmail( info2.getOwner().getEmail() )); - - assertNotNull( dor.manager.lookupOrgUserByUsername( info1.getOwner().getUsername() )); - assertNotNull( dor.manager.lookupOrgUserByUsername( info2.getOwner().getUsername() )); - - } else { - - assertNull( dor.manager.getOrgUser( info1.getOwner().getUuid() ) ); - assertNull( dor.manager.getOrgUser( info2.getOwner().getUuid() ) ); - - assertNull( dor.manager.lookupOrgUserByEmail( info1.getOwner().getEmail() ) ); - assertNull( dor.manager.lookupOrgUserByEmail( info2.getOwner().getEmail() ) ); - - assertNull( dor.manager.lookupOrgUserByUsername( info1.getOwner().getUsername() ) ); - assertNull( dor.manager.lookupOrgUserByUsername( info2.getOwner().getUsername() ) ); - } - } - - - @org.junit.Test - public void testManagerOrgUserUpdateMethod() throws Exception { - - // create an org with an admin user - final String random1 = org.apache.commons.lang.RandomStringUtils.randomAlphanumeric( 10 ); - final OrganizationOwnerInfo orgOwnerInfo1 = setup.getMgmtSvc().createOwnerAndOrganization( - "org_" + random1, "user_" + random1, "user_" + random1, - "user_" + random1 + "@example.com", "password" ); - - DuplicateAdminUserRepair dor = new DuplicateAdminUserRepair(setup.getEmf(), setup.getMgmtSvc()); - dor.manager = dor.createNewRepairManager(); // test the real manager - - // start the tool so that Spring, Cassandra, etc/ gets initialized - dor.startTool( new String[]{"-dryrun", "true"}, false ); // false means do not call System.exit() - - UserInfo userInfo = setup.getMgmtSvc().getAdminUserByUuid( orgOwnerInfo1.getOwner().getUuid() ); - OrgUser user = dor.manager.getOrgUser( orgOwnerInfo1.getOwner().getUuid() ); - assertEquals( userInfo.getUsername(), user.getUsername()); - assertEquals( userInfo.getEmail(), user.getEmail()); - - // change user's username using updateOrgUser() - String newUsername = "boom_" + random1; - user.setUsername(newUsername); - dor.manager.updateOrgUser( user ); - user = dor.manager.getOrgUser( orgOwnerInfo1.getOwner().getUuid() ); - assertEquals( newUsername, user.getUsername()); - - // change user's username using setOrgUserName() - newUsername = "blammo_" + random1; - dor.manager.setOrgUserName( user, newUsername ); - user = dor.manager.getOrgUser( orgOwnerInfo1.getOwner().getUuid() ); - assertEquals( newUsername, user.getUsername()); - } - - - /** - * Extend mock manager to add a pair of duplicate users. - */ - static class MockManager extends MockUserOrgManager { - - OrgUser user1_a; - OrgUser user1_b; - OrgUser user2_a; - OrgUser user2_b; - - public MockManager() throws Exception { - - super(1); // ask parent to create one pair of duplicate orgs - - Org org = orgsById.values().iterator().next(); - - String sfx = RandomStringUtils.randomAlphanumeric(10); - - // user1 a and b have duplicate usernames AND DUPLICATE EMAIL ADDRESSES - - user1_a = createOrgUser( UUID.randomUUID(), "UserName_"+sfx, "UserName_"+sfx+"@example.com" ); - addUserToOrg( user1_a, org ); - pause(100); - - user1_b = createOrgUser( UUID.randomUUID(), "Username_"+sfx, "Username_"+sfx+"@example.com" ); - addUserToOrg( user1_b, org ); - pause(100); - - // user2 a and b have duplicate usernames AND DIFFERENT EMAIL ADDRESSES - - user2_a = createOrgUser( UUID.randomUUID(), "UserName_"+sfx, "UserName_"+sfx+"@example.com" ); - addUserToOrg( user2_a, org ); - pause(100); - - user2_b = createOrgUser( UUID.randomUUID(), "UserName_"+sfx, "UserName_"+sfx+"@example.com" ); - addUserToOrg( user2_b, org ); - pause(100); - - } - - } - -} http://git-wip-us.apache.org/repos/asf/usergrid/blob/ceb81076/stack/tools/src/test/java/org/apache/usergrid/tools/MockUserOrgManager.java ---------------------------------------------------------------------- diff --git a/stack/tools/src/test/java/org/apache/usergrid/tools/MockUserOrgManager.java b/stack/tools/src/test/java/org/apache/usergrid/tools/MockUserOrgManager.java index 4b50f43..818c1b8 100644 --- a/stack/tools/src/test/java/org/apache/usergrid/tools/MockUserOrgManager.java +++ b/stack/tools/src/test/java/org/apache/usergrid/tools/MockUserOrgManager.java @@ -169,7 +169,7 @@ class MockUserOrgManager implements UserOrgInterface { for (String orgName : duplicatesByName.keySet()) { Set<Org> orgs = duplicatesByName.get( orgName ); for (Org org : orgs) { - DuplicateAdminUserRepairTest.logger.info( "Duplicate org {}:{}", orgName, org.getId() ); + DuplicateAdminRepairTest.logger.info( "Duplicate org {}:{}", orgName, org.getId() ); } } }
