You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@usergrid.apache.org by mr...@apache.org on 2015/12/17 23:14:20 UTC
[1/7] usergrid git commit: Duplicate org repair tools,
and implementation for
managementService.removeOrganizationApplication().
Repository: usergrid
Updated Branches:
refs/heads/1.x ccf4e4231 -> 69eeb9187
Duplicate org repair tools, and implementation for managementService.removeOrganizationApplication().
Project: http://git-wip-us.apache.org/repos/asf/usergrid/repo
Commit: http://git-wip-us.apache.org/repos/asf/usergrid/commit/674532f4
Tree: http://git-wip-us.apache.org/repos/asf/usergrid/tree/674532f4
Diff: http://git-wip-us.apache.org/repos/asf/usergrid/diff/674532f4
Branch: refs/heads/1.x
Commit: 674532f4d8011afa5b44178467af2fefa3319dea
Parents: 98658fd
Author: Dave Johnson <sn...@apache.org>
Authored: Fri Dec 11 12:21:19 2015 -0500
Committer: Dave Johnson <sn...@apache.org>
Committed: Fri Dec 11 12:21:19 2015 -0500
----------------------------------------------------------------------
.../usergrid/management/ManagementService.java | 4 +-
.../cassandra/ManagementServiceImpl.java | 28 +-
.../usergrid/tools/DuplicateOrgInterface.java | 110 +++++
.../usergrid/tools/DuplicateOrgRepair.java | 494 +++++++++++++++++++
.../usergrid/tools/DuplicateOrgRepairTest.java | 400 +++++++++++++++
5 files changed, 1032 insertions(+), 4 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/usergrid/blob/674532f4/stack/services/src/main/java/org/apache/usergrid/management/ManagementService.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/management/ManagementService.java b/stack/services/src/main/java/org/apache/usergrid/management/ManagementService.java
index b5537ec..4b0cbfd 100644
--- a/stack/services/src/main/java/org/apache/usergrid/management/ManagementService.java
+++ b/stack/services/src/main/java/org/apache/usergrid/management/ManagementService.java
@@ -68,7 +68,9 @@ public interface ManagementService {
public UserInfo createAdminFromPrexistingPassword( User user, CredentialsInfo ci ) throws Exception;
- public ApplicationInfo createApplication( UUID organizationId, String applicationName ) throws Exception;
+ void removeAdminUserFromOrganization(UUID userId, UUID organizationId, boolean force) throws Exception;
+
+ public ApplicationInfo createApplication(UUID organizationId, String applicationName ) throws Exception;
public ApplicationInfo createApplication( UUID organizationId, String applicationName,
Map<String, Object> properties ) throws Exception;
http://git-wip-us.apache.org/repos/asf/usergrid/blob/674532f4/stack/services/src/main/java/org/apache/usergrid/management/cassandra/ManagementServiceImpl.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/management/cassandra/ManagementServiceImpl.java b/stack/services/src/main/java/org/apache/usergrid/management/cassandra/ManagementServiceImpl.java
index cb19733..3cdc806 100644
--- a/stack/services/src/main/java/org/apache/usergrid/management/cassandra/ManagementServiceImpl.java
+++ b/stack/services/src/main/java/org/apache/usergrid/management/cassandra/ManagementServiceImpl.java
@@ -28,6 +28,7 @@ import java.util.Properties;
import java.util.Set;
import java.util.UUID;
+import org.apache.usergrid.persistence.cassandra.ConnectionRefImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -1594,6 +1595,12 @@ public class ManagementServiceImpl implements ManagementService {
@Override
public void removeAdminUserFromOrganization( UUID userId, UUID organizationId ) throws Exception {
+ removeAdminUserFromOrganization( userId, organizationId, false );
+ }
+
+
+ @Override
+ public void removeAdminUserFromOrganization( UUID userId, UUID organizationId, boolean force ) throws Exception {
if ( ( userId == null ) || ( organizationId == null ) ) {
return;
@@ -1602,8 +1609,10 @@ public class ManagementServiceImpl implements ManagementService {
EntityManager em = emf.getEntityManager( MANAGEMENT_APPLICATION_ID );
try {
- if ( em.getCollection( new SimpleEntityRef( Group.ENTITY_TYPE, organizationId ), "users", null, 2,
- Level.IDS, false ).size() <= 1 ) {
+ int size = em.getCollection( new SimpleEntityRef( Group.ENTITY_TYPE, organizationId ),
+ "users", null, 2, Level.IDS, false ).size();
+
+ if ( !force && size <= 1 ) {
throw new Exception();
}
}
@@ -1751,10 +1760,23 @@ public class ManagementServiceImpl implements ManagementService {
}
+ /**
+ * Remove application from an organization.
+ */
@Override
public void removeOrganizationApplication( UUID organizationId, UUID applicationId ) throws Exception {
- // TODO Auto-generated method stub
+ if ( ( organizationId == null ) || ( applicationId == null ) ) {
+ return;
+ }
+ EntityManager em = emf.getEntityManager( MANAGEMENT_APPLICATION_ID );
+ em.deleteConnection( new ConnectionRefImpl(
+ "group", // String connectingEntityType
+ organizationId, // UUID connectingEntityId
+ "owns", // String connectionType
+ APPLICATION_INFO, // String connectedEntityType
+ applicationId // UUID connectedEntityId
+ ) );
}
http://git-wip-us.apache.org/repos/asf/usergrid/blob/674532f4/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateOrgInterface.java
----------------------------------------------------------------------
diff --git a/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateOrgInterface.java b/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateOrgInterface.java
new file mode 100644
index 0000000..596d55e
--- /dev/null
+++ b/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateOrgInterface.java
@@ -0,0 +1,110 @@
+/*
+ * 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 rx.Observable;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+
+
+/**
+ * Abstraction to make duplicate org repair testable.
+ */
+interface DuplicateOrgInterface {
+
+ Observable<Org> getOrgs() throws Exception;
+
+ Observable<OrgUser> getUsers() throws Exception;
+
+ Set<Org> getUsersOrgs(OrgUser user) throws Exception;
+
+ Set<OrgUser> getOrgUsers(Org org ) throws Exception;
+
+ void removeOrg(Org keeper, Org duplicate) throws Exception;
+
+ void removeUserFromOrg( OrgUser user, Org org ) throws Exception;
+
+ void addUserToOrg( OrgUser user, Org org ) throws Exception;
+
+ Set<UUID> getOrgApps(Org org) throws Exception;
+
+ void removeAppFromOrg( UUID appId, Org org ) throws Exception;
+
+ void addAppToOrg( UUID appId, Org org ) throws Exception;
+
+ void logDuplicates(Map<String, Set<Org>> duplicatesByName);
+
+ class Org implements Comparable<Org> {
+ private UUID id;
+ private String name;
+ private long created;
+ public Object sourceValue;
+
+ public Org( UUID id, String name, long created ) {
+ this.id = id;
+ this.name = name;
+ this.created = created;
+ }
+
+ @Override
+ public boolean equals( Object o ) {
+ if ( o instanceof Org ) {
+ Org other = (Org)o;
+ return getId().equals( other.getId() );
+ }
+ return false;
+ }
+
+ @Override
+ public int compareTo(Org o) {
+ return Long.compare( this.created, o.created );
+ }
+
+ public UUID getId() {
+ return id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public long getCreated() {
+ return created;
+ }
+ }
+
+ class OrgUser {
+ private UUID id;
+ private String name;
+ public Object sourceValue;
+
+ public OrgUser( UUID id, String name ) {
+ this.id = id;
+ this.name = name;
+ }
+
+ public UUID getId() {
+ return id;
+ }
+
+ public String getName() {
+ return name;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/usergrid/blob/674532f4/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateOrgRepair.java
----------------------------------------------------------------------
diff --git a/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateOrgRepair.java b/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateOrgRepair.java
new file mode 100644
index 0000000..bc4acb5
--- /dev/null
+++ b/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateOrgRepair.java
@@ -0,0 +1,494 @@
+/*
+ * 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.BiMap;
+import com.google.common.collect.Sets;
+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.RandomStringUtils;
+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.cassandra.CassandraService;
+import org.apache.usergrid.persistence.entities.Group;
+import org.apache.usergrid.utils.StringUtils;
+import rx.Observable;
+import rx.Scheduler;
+import rx.Subscriber;
+import rx.functions.Action1;
+import rx.schedulers.Schedulers;
+
+import java.util.*;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import static org.apache.usergrid.tools.DuplicateOrgInterface.Org;
+import static org.apache.usergrid.tools.DuplicateOrgInterface.OrgUser;
+
+/**
+ * Find duplicate orgs, delete all but oldest of each and assign users to it.
+ */
+public class DuplicateOrgRepair extends ToolBase {
+
+ DuplicateOrgInterface manager = new Manager();
+
+ Map<String, Set<Org>> orgsByName = new HashMap<String, Set<Org>>();
+
+ Map<UUID, Org> orgsById = new HashMap<UUID, Org>();
+
+ Map<OrgUser, Set<Org>> orgsByUser = new HashMap<OrgUser, Set<Org>>();
+
+ Map<String, Set<Org>> duplicatesByName = new HashMap<String, Set<Org>>();
+
+ static final String THREADS_ARG_NAME = "threads";
+
+ static int threadCount = 5;
+
+ static final String DRYRUN_ARG_NAME = "dryrun";
+
+ static boolean dryRun = false;
+
+
+ @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;
+ }
+
+ @Override
+ public void runTool(CommandLine line) throws Exception {
+
+ logger.info( "DuplicateOrgRepair tool starting up..." );
+
+ startSpring();
+ setVerbose( line );
+
+ dryRun = Boolean.parseBoolean( line.getOptionValue( DRYRUN_ARG_NAME ));
+
+ 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;
+ }
+ }
+
+ buildOrgMaps();
+
+ augmentUserOrgsMap();
+
+ mergeDuplicateOrgs();
+
+ removeDuplicateOrgs();
+
+ logger.info( "DuplicateOrgRepair work is done." );
+ }
+
+
+ /**
+ * build map of orgs by name, orgs by id, orgs by user and duplicate orgs by name
+ */
+ private void buildOrgMaps() throws Exception {
+
+ manager.getOrgs().doOnNext( new Action1<Org>() {
+ @Override
+ public void call(Org org) {
+
+ // orgs by name and duplicate orgs by name maps
+
+ Set<Org> orgs = orgsByName.get( org.getName() );
+ if (orgs == null) {
+ orgs = new HashSet<Org>();
+ orgsByName.put( org.getName(), orgs );
+ } else {
+ duplicatesByName.put( org.getName(), orgs );
+ }
+ orgs.add( org );
+
+ orgsById.put( org.getId(), org );
+
+ // orgs by user map, created via org -> user connections
+
+ try {
+ Set<OrgUser> orgUsers = manager.getOrgUsers( org );
+ for ( OrgUser user : orgUsers ) {
+ Set<Org> usersOrgs = orgsByUser.get( user );
+ if (usersOrgs == null) {
+ usersOrgs = new HashSet<Org>();
+ orgsByUser.put( user, usersOrgs );
+ }
+ usersOrgs.add( org );
+ }
+ } catch (Exception e) {
+ logger.error("Error getting users for org {}:{}", org.getName(), org.getId());
+ }
+
+ }
+ } ).toBlocking().lastOrDefault( null );
+ }
+
+
+ /**
+ * augment user orgs map via user -> org connections
+ */
+ private void augmentUserOrgsMap() throws Exception {
+
+ ExecutorService writeThreadPoolExecutor = Executors.newFixedThreadPool( threadCount );
+ Scheduler scheduler = Schedulers.from( writeThreadPoolExecutor );
+
+ manager.getUsers().doOnNext( new Action1<OrgUser>() {
+ @Override
+ public void call(OrgUser user) {
+ try {
+ Set<Org> connectedToOrgs = manager.getUsersOrgs(user);
+ Set<Org> usersOrgs = orgsByUser.get(user);
+ for ( Org org : connectedToOrgs ) {
+ if (!usersOrgs.contains(org)) {
+ usersOrgs.add(org);
+ }
+ }
+
+ } catch (Exception e) {
+ logger.error("Error getting orgs for user {}:{}", user.getName(), user.getId());
+ }
+ }
+ } ).subscribeOn( scheduler ).toBlocking().lastOrDefault( null );
+ }
+
+
+ /**
+ * For each duplicate name, pick best org and merge apps and users into it
+ */
+ private void mergeDuplicateOrgs() throws Exception {
+
+ for ( String dupName : duplicatesByName.keySet() ) {
+ Set<Org> duplicateOrgs = duplicatesByName.get(dupName);
+ Org bestOrg = selectBest( duplicateOrgs );
+
+ for ( Org org : duplicateOrgs ) {
+
+ if ( !org.equals( bestOrg )) {
+
+ Set<OrgUser> orgUsers = new HashSet<OrgUser>( manager.getOrgUsers( org ));
+
+ for ( OrgUser user : orgUsers ) {
+ if (dryRun) {
+ Object[] args = new Object[] {
+ user.getName(), user.getId(), bestOrg.getName(), bestOrg.getId()};
+ logger.info( "Would add user {}:{} to org {}:{}", args);
+ args = new Object[] {
+ user.getName(), user.getId(), org.getName(), org.getId()};
+ logger.info( "Would remove user {}:{} org {}:{}", args);
+ continue;
+ }
+ manager.addUserToOrg( user, bestOrg );
+ manager.removeUserFromOrg( user, org );
+ }
+
+ Set<UUID> orgApps = new HashSet<UUID>( manager.getOrgApps( org ));
+
+ for ( UUID appId : orgApps ) {
+ if (dryRun) {
+ Object[] args = new Object[] {
+ appId, bestOrg.getName(), bestOrg.getId()};
+ logger.info( "Would add app {} to org {}:{}", args);
+ args = new Object[] {
+ appId, org.getName(), org.getId()};
+ logger.info( "Would remove app {} org {}:{}", args);
+ continue;
+ }
+ manager.addAppToOrg( appId, bestOrg );
+ manager.removeAppFromOrg( appId, org );
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * remove/rename duplicate orgs so they no longer impact operation of system
+ */
+ private void removeDuplicateOrgs() throws Exception {
+ for ( String dupName : duplicatesByName.keySet() ) {
+ Set<Org> orgs = duplicatesByName.get( dupName );
+ Org best = selectBest( orgs );
+ for ( Org candidate : orgs ) {
+ if ( !candidate.equals(best) ) {
+ if ( dryRun ) {
+ logger.info("Would rename/remove org {}:{}",
+ new Object[] { candidate.getName(), candidate.getId() });
+ } else {
+ manager.removeOrg( best, candidate );
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * select best org from a set of duplicates by picking the oldest org
+ */
+ public Org selectBest(Set<Org> orgs) throws Exception {
+ Org oldest = null;
+ for ( Org org :orgs ) {
+ if ( oldest == null || org.compareTo( oldest ) < 0 ) {
+ oldest = org;
+ }
+ }
+ return oldest;
+ }
+
+
+ class Manager implements DuplicateOrgInterface {
+
+ private boolean dryRun = true;
+
+ @Override
+ public Observable<Org> getOrgs() throws Exception {
+
+ return Observable.create( new Observable.OnSubscribe<Org>() {
+
+ @Override
+ public void call(Subscriber<? super Org> subscriber) {
+ subscriber.onStart();
+ try {
+ Query query = new Query();
+ query.setLimit( MAX_ENTITY_FETCH );
+ query.setResultsLevel( Results.Level.ALL_PROPERTIES );
+ EntityManager em = emf.getEntityManager( CassandraService.MANAGEMENT_APPLICATION_ID );
+ Results results = em.searchCollection( em.getApplicationRef(), "groups", query );
+
+ while (results.size() > 0) {
+ for (Entity orgEntity : results.getList()) {
+
+ Org org = new Org(
+ orgEntity.getUuid(),
+ orgEntity.getProperty( "path" )+"",
+ orgEntity.getCreated() );
+ org.sourceValue = orgEntity;
+
+ subscriber.onNext( org );
+
+ // logger.info( "org: {}, \"{}\", {}", new Object[]{
+ // orgEntity.getProperty( "path" ),
+ // orgEntity.getUuid(),
+ // orgEntity.getCreated()} );
+ }
+ if (results.getCursor() == null) {
+ break;
+ }
+ query.setCursor( results.getCursor() );
+ results = em.searchCollection( em.getApplicationRef(), "groups", query );
+ }
+
+ } catch (Exception e) {
+ subscriber.onError( e );
+ }
+ subscriber.onCompleted();
+ }
+ } );
+ }
+
+ @Override
+ public Observable<OrgUser> getUsers() throws Exception {
+
+ return Observable.create( new Observable.OnSubscribe<OrgUser>() {
+
+ @Override
+ public void call(Subscriber<? super OrgUser> subscriber) {
+ subscriber.onStart();
+ try {
+ Query query = new Query();
+ query.setLimit( MAX_ENTITY_FETCH );
+ query.setResultsLevel( Results.Level.ALL_PROPERTIES );
+ EntityManager em = emf.getEntityManager( CassandraService.MANAGEMENT_APPLICATION_ID );
+ Results results = em.searchCollection( em.getApplicationRef(), "users", query );
+
+ while (results.size() > 0) {
+ for (Entity entity : results.getList()) {
+
+ OrgUser orgUser = new OrgUser(
+ entity.getUuid(),
+ entity.getProperty( "username" ) + "" );
+ orgUser.sourceValue = entity;
+
+ subscriber.onNext( orgUser );
+
+ // logger.info( "org: {}, \"{}\", {}", new Object[]{
+ // entity.getProperty( "path" ),
+ // entity.getUuid(),
+ // entity.getCreated()} );
+ }
+ if (results.getCursor() == null) {
+ break;
+ }
+ query.setCursor( results.getCursor() );
+ results = em.searchCollection( em.getApplicationRef(), "users", query );
+ }
+
+ } catch (Exception e) {
+ subscriber.onError( e );
+ }
+ subscriber.onCompleted();
+ }
+ } );
+ }
+
+ @Override
+ public Set<Org> getUsersOrgs(OrgUser user) throws Exception {
+
+ Set<Org> ret = new HashSet<Org>();
+
+ Map<String, Object> orgData = managementService.getAdminUserOrganizationData( user.getId() );
+
+ Map<String, Object> orgs = (Map<String, Object>)orgData.get("organizations");
+ for ( String orgName : orgs.keySet() ) {
+
+ Map<String, Object> orgMap = (Map<String, Object>)orgs.get( orgName );
+ Group group = managementService.getOrganizationProps(
+ UUID.fromString( orgMap.get( "uuid" ).toString() ) );
+
+ Org org = new Org(
+ group.getUuid(),
+ group.getPath(),
+ group.getCreated()
+ );
+ ret.add(org);
+ }
+
+ return ret;
+ }
+
+
+ @Override
+ public void removeOrg(Org keeper, Org duplicate) throws Exception {
+
+ // we don't have a remove org API so rename org so that it is no longer a duplicate
+
+ OrganizationInfo orgInfo = managementService.getOrganizationByUuid( duplicate.getId() );
+ orgInfo.setName( "dup_" + keeper.getId() + "_" + RandomStringUtils.randomAlphanumeric(10) );
+ managementService.updateOrganization( orgInfo );
+ }
+
+
+ @Override
+ public Set<OrgUser> getOrgUsers(Org org) throws Exception {
+
+ Set<OrgUser> ret = new HashSet<OrgUser>();
+
+ List<UserInfo> userInfos = managementService.getAdminUsersForOrganization( org.getId() );
+
+ for ( UserInfo userInfo : userInfos ) {
+ OrgUser orgUser = new OrgUser( userInfo.getUuid(), userInfo.getUsername() );
+ ret.add(orgUser);
+ }
+
+ return ret;
+ }
+
+
+ @Override
+ public void removeUserFromOrg(OrgUser user, Org org) throws Exception {
+ // forcefully remove admin user from org
+ managementService.removeAdminUserFromOrganization( user.getId(), org.getId(), true );
+ }
+
+
+ @Override
+ public void addUserToOrg(OrgUser user, Org org) throws Exception {
+ UserInfo userInfo = managementService.getAdminUserByUsername( user.getName() );
+ OrganizationInfo orgInfo = managementService.getOrganizationByUuid( org.getId() );
+ managementService.addAdminUserToOrganization( userInfo, orgInfo, false );
+ }
+
+
+ @Override
+ public Set<UUID> getOrgApps(Org org) throws Exception {
+ BiMap<UUID, String> apps = managementService.getApplicationsForOrganization( org.getId() );
+ return apps.keySet();
+ }
+
+
+ @Override
+ public void removeAppFromOrg(UUID appId, Org org) throws Exception {
+ managementService.removeOrganizationApplication( org.getId(), appId );
+ }
+
+
+ @Override
+ public void addAppToOrg(UUID appId, Org org) throws Exception {
+ managementService.addApplicationToOrganization( org.getId(), appId );
+ }
+
+
+ @Override
+ public void logDuplicates(Map<String, Set<Org>> duplicatesByName) {
+
+ for ( String orgName : duplicatesByName.keySet() ) {
+ Set<Org> orgs = duplicatesByName.get(orgName);
+ for ( Org org : orgs ) {
+ Entity orgEntity = (Entity)org.sourceValue;
+
+ StringBuilder sb = new StringBuilder();
+ sb.append(orgEntity.toString()).append(", ");
+
+ try {
+ BiMap<UUID, String> apps =
+ managementService.getApplicationsForOrganization( orgEntity.getUuid() );
+ String sep = "";
+ for ( UUID uuid : apps.keySet() ) {
+ String appName = apps.get(uuid);
+ sb.append(appName).append(":").append(uuid).append(sep);
+ sep = ", ";
+ }
+
+ } catch (Exception e) {
+ logger.error("Error getting applications for org {}:{}", org.getName(), org.getId() );
+ }
+
+ logger.info(sb.toString());
+ }
+ }
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/usergrid/blob/674532f4/stack/tools/src/test/java/org/apache/usergrid/tools/DuplicateOrgRepairTest.java
----------------------------------------------------------------------
diff --git a/stack/tools/src/test/java/org/apache/usergrid/tools/DuplicateOrgRepairTest.java b/stack/tools/src/test/java/org/apache/usergrid/tools/DuplicateOrgRepairTest.java
new file mode 100644
index 0000000..ac95748
--- /dev/null
+++ b/stack/tools/src/test/java/org/apache/usergrid/tools/DuplicateOrgRepairTest.java
@@ -0,0 +1,400 @@
+/*
+ * 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.lang.RandomStringUtils;
+import org.apache.usergrid.ServiceITSetup;
+import org.apache.usergrid.ServiceITSetupImpl;
+import org.apache.usergrid.ServiceITSuite;
+import org.apache.usergrid.management.ApplicationInfo;
+import org.apache.usergrid.management.OrganizationOwnerInfo;
+import org.junit.ClassRule;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import rx.Observable;
+import rx.functions.Action1;
+
+import java.util.*;
+
+import static junit.framework.Assert.assertTrue;
+import static org.apache.usergrid.tools.DuplicateOrgInterface.Org;
+import static org.apache.usergrid.tools.DuplicateOrgInterface.OrgUser;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+
+/**
+ * Test duplicate org repair.
+ */
+public class DuplicateOrgRepairTest {
+ static final Logger logger = LoggerFactory.getLogger( DuplicateOrgRepairTest.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 {
+
+ int numOrgs = 10; // create 10 orgs and a dup for each
+
+ final DuplicateOrgRepair dor = new DuplicateOrgRepair();
+ dor.manager = new Manager( numOrgs );
+
+ assertEquals( "must start with dups",
+ 2 * numOrgs, (long)dor.manager.getOrgs().count().toBlocking().single());
+
+ dor.startTool( new String[] {}, false ); // false means do not call System.exit()
+
+ assertEquals( "must remove dups",
+ numOrgs, (long)dor.manager.getOrgs().count().toBlocking().single());
+
+ dor.manager.getOrgs().doOnNext( new Action1<Org>() {
+ @Override
+ public void call(Org org) {
+ try {
+ assertEquals("remaining orgs should have right number of users",
+ 3, dor.manager.getOrgUsers(org).size());
+
+ assertEquals("remaining orgs should have right number of apps",
+ 3, dor.manager.getOrgApps(org).size());
+
+ } catch (Exception e) {
+ logger.error("Error counting apps or users: " + e.getMessage(), e);
+ fail("Error counting apps or users");
+ }
+ }
+ }).toBlocking().lastOrDefault( null );
+ }
+
+
+ @org.junit.Test
+ public void testMockWithDupsDryRun() throws Exception {
+
+ int numOrgs = 10; // create 10 orgs and a dup for each
+
+ DuplicateOrgRepair dor = new DuplicateOrgRepair();
+ dor.manager = new Manager( numOrgs );
+
+ assertEquals( "must start with dups",
+ 2 * numOrgs, (long)dor.manager.getOrgs().count().toBlocking().single());
+
+ dor.startTool( new String[] { "-dryrun", "true" }, false ); // false means do not call System.exit()
+
+ assertEquals( "must detect right number of dups",
+ numOrgs, dor.duplicatesByName.keySet().size() );
+
+ assertEquals( "dryrun must not remove dups",
+ 2 * numOrgs, (long)dor.manager.getOrgs().count().toBlocking().single());
+ }
+
+
+ /**
+ * 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 = RandomStringUtils.randomAlphanumeric( 10 );
+ final OrganizationOwnerInfo orgOwnerInfo1 = setup.getMgmtSvc().createOwnerAndOrganization(
+ "org_" + random1, "user_" + random1, "user_" + random1,
+ "user_" + random1 + "@example.com", "password" );
+
+ final String random2 = 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 );
+
+ DuplicateOrgRepair dor = new DuplicateOrgRepair();
+
+ dor.startTool( new String[] {}, false ); // false means do not call System.exit()
+
+ dor.startTool( new String[] { "dryrun", "true" }, false ); // false means do not call System.exit()
+
+ assertTrue(true); // we're happy if we get to this point
+ }
+
+
+ @org.junit.Test
+ public void testManagerAddUserToOrg() throws Exception {
+
+ // create two orgs each with owning user
+
+ final String random1 = RandomStringUtils.randomAlphanumeric( 10 );
+ final OrganizationOwnerInfo orgOwnerInfo1 = setup.getMgmtSvc().createOwnerAndOrganization(
+ "org_" + random1, "user_" + random1, "user_" + random1,
+ "user_" + random1 + "@example.com", "password" );
+
+ final String random2 = RandomStringUtils.randomAlphanumeric( 10 );
+ final OrganizationOwnerInfo orgOwnerInfo2 = setup.getMgmtSvc().createOwnerAndOrganization(
+ "org_" + random2, "user_" + random2, "user_" + random2,
+ "user_" + random2 + "@example.com", "password" );
+
+ DuplicateOrgRepair dor = new DuplicateOrgRepair();
+
+ // start the tool so thaht Spring, Cassandra, etc/ gets initialized
+ dor.startTool( new String[] { "-dryrun", "true" }, false ); // false means do not call System.exit()
+
+ Org org1 = new Org(
+ orgOwnerInfo1.getOrganization().getUuid(), orgOwnerInfo1.getOrganization().getName(), 0L);
+
+ Org org2 = new Org(
+ orgOwnerInfo2.getOrganization().getUuid(), orgOwnerInfo2.getOrganization().getName(), 0L);
+
+ OrgUser user1 = new OrgUser(
+ orgOwnerInfo1.getOwner().getUuid(), orgOwnerInfo1.getOwner().getUsername());
+
+ OrgUser user2 = new OrgUser(
+ orgOwnerInfo2.getOwner().getUuid(), orgOwnerInfo2.getOwner().getUsername());
+
+ assertEquals( 1, dor.manager.getUsersOrgs( user1 ).size());
+ assertEquals( 1, dor.manager.getOrgUsers( org1 ).size());
+ assertEquals( 1, dor.manager.getOrgUsers( org2 ).size());
+
+ dor.manager.addUserToOrg( user1, org2 );
+
+ assertEquals( 2, dor.manager.getUsersOrgs( user1 ).size());
+ assertEquals( 1, dor.manager.getOrgUsers( org1 ).size() );
+ assertEquals( 2, dor.manager.getOrgUsers( org2 ).size() );
+
+ dor.manager.removeUserFromOrg( user1, org2 );
+
+ assertEquals( 1, dor.manager.getUsersOrgs( user1 ).size());
+ assertEquals( 1, dor.manager.getOrgUsers( org1 ).size());
+ assertEquals( 1, dor.manager.getOrgUsers( org2 ).size() );
+ }
+
+
+
+ @org.junit.Test
+ public void testManagerAddAppToOrg() throws Exception {
+
+ // create two orgs each with owning user
+
+ final String random1 = RandomStringUtils.randomAlphanumeric( 10 );
+ final OrganizationOwnerInfo orgOwnerInfo1 = setup.getMgmtSvc().createOwnerAndOrganization(
+ "org_" + random1, "user_" + random1, "user_" + random1,
+ "user_" + random1 + "@example.com", "password" );
+
+ final String random2 = RandomStringUtils.randomAlphanumeric( 10 );
+ final OrganizationOwnerInfo orgOwnerInfo2 = setup.getMgmtSvc().createOwnerAndOrganization(
+ "org_" + random2, "user_" + random2, "user_" + random2,
+ "user_" + random2 + "@example.com", "password" );
+
+ ApplicationInfo app11 = setup.getMgmtSvc().createApplication(
+ orgOwnerInfo1.getOrganization().getUuid(), "app_" + RandomStringUtils.randomAlphanumeric( 10 ) );
+
+ ApplicationInfo app12= setup.getMgmtSvc().createApplication(
+ orgOwnerInfo1.getOrganization().getUuid(), "app_" + RandomStringUtils.randomAlphanumeric( 10 ));
+
+ ApplicationInfo app21 = setup.getMgmtSvc().createApplication(
+ orgOwnerInfo2.getOrganization().getUuid(), "app_" + RandomStringUtils.randomAlphanumeric( 10 ));
+
+ DuplicateOrgRepair dor = new DuplicateOrgRepair();
+
+ // start the tool so that Spring, Cassandra, etc/ gets initialized
+ dor.startTool( new String[] { "-dryrun", "true" }, false ); // false means do not call System.exit()
+
+ Org org1 = new Org(
+ orgOwnerInfo1.getOrganization().getUuid(), orgOwnerInfo1.getOrganization().getName(), 0L);
+
+ Org org2 = new Org(
+ orgOwnerInfo2.getOrganization().getUuid(), orgOwnerInfo2.getOrganization().getName(), 0L);
+
+ assertEquals( 2, dor.manager.getOrgApps( org1 ).size() );
+ assertEquals( 1, dor.manager.getOrgApps( org2 ).size() );
+
+ dor.manager.removeAppFromOrg( app12.getId(), org1 );
+
+ assertEquals( 1, dor.manager.getOrgApps( org1 ).size() );
+ assertEquals( 1, dor.manager.getOrgApps( org2 ).size() );
+
+ dor.manager.addAppToOrg( app12.getId(), org2 );
+
+ assertEquals( 1, dor.manager.getOrgApps( org1 ).size() );
+ assertEquals( 2, dor.manager.getOrgApps( org2 ).size() );
+ }
+
+
+ /**
+ * Mock manager implementation for testing.
+ */
+ class Manager implements DuplicateOrgInterface {
+
+ Set<Org> orgs;
+
+ Set<OrgUser> orgUsers;
+
+ Map<Org, Set<OrgUser>> usersByOrg = new HashMap<Org, Set<OrgUser>>();
+
+ Map<OrgUser, Set<Org>> orgsByUser = new HashMap<OrgUser, Set<Org>>();
+
+ Map<Org, Set<UUID>> appsByOrg = new HashMap<Org, Set<UUID>>();
+
+
+ /**
+ * Populate manager with orgs and users.
+ * Will create a number of orgs and a duplicate for each.
+ *
+ * @param numOrgs One half of the number of orgs to create.
+ */
+ public Manager(int numOrgs) {
+
+ for (int i = 0; i < numOrgs; i++) {
+
+ // each org name is duplicated once another org created 20 ms apart
+
+ Org org1 = new Org( UUID.randomUUID(), "org_" + i, System.currentTimeMillis() );
+ try {
+ Thread.sleep( 100 );
+ } catch (InterruptedException intentionallyIgnored) {
+ }
+ Org org2 = new Org( UUID.randomUUID(), "org_" + i, System.currentTimeMillis() );
+
+ OrgUser usera = new OrgUser( UUID.randomUUID(), "user_" + i + "_a" );
+ OrgUser userb = new OrgUser( UUID.randomUUID(), "user_" + i + "_b" );
+ OrgUser userc = new OrgUser( UUID.randomUUID(), "user_" + i + "_c" );
+
+ // add users to orgs
+
+ Set<OrgUser> org1Users = new HashSet<OrgUser>();
+ org1Users.add( usera );
+ org1Users.add( userb );
+ usersByOrg.put( org1, org1Users );
+
+ Set<OrgUser> org2Users = new HashSet<OrgUser>();
+ org2Users.add( userc );
+ usersByOrg.put( org2, org2Users );
+
+ // add orgs to users
+
+ Set<Org> useraOrgs = new HashSet<Org>();
+ useraOrgs.add( org1 );
+ orgsByUser.put( usera, useraOrgs );
+
+ Set<Org> userbOrgs = new HashSet<Org>();
+ userbOrgs.add( org1 );
+ orgsByUser.put( userb, userbOrgs );
+
+ Set<Org> usercOrgs = new HashSet<Org>();
+ usercOrgs.add( org2 );
+ orgsByUser.put( userc, usercOrgs );
+
+ // add some apps to the orgs
+
+ Set<UUID> org1apps = new HashSet<UUID>();
+ org1apps.add( UUID.randomUUID() );
+ org1apps.add( UUID.randomUUID() );
+ appsByOrg.put( org1, org1apps );
+
+ Set<UUID> org2apps = new HashSet<UUID>();
+ org2apps.add( UUID.randomUUID() );
+ appsByOrg.put( org2, org2apps );
+ }
+ }
+
+
+ @Override
+ public Observable<Org> getOrgs() throws Exception {
+ return Observable.from( usersByOrg.keySet() );
+ }
+
+ @Override
+ public Observable<OrgUser> getUsers() throws Exception {
+ return Observable.from( orgsByUser.keySet() );
+ }
+
+ @Override
+ public Set<Org> getUsersOrgs(OrgUser user) {
+ return orgsByUser.get( user );
+ }
+
+ @Override
+ public void removeOrg(Org keeper, Org duplicate) throws Exception {
+ Set<OrgUser> users = usersByOrg.get( duplicate );
+ for (OrgUser user : users) {
+ Set<Org> userOrgs = orgsByUser.get( user );
+ userOrgs.remove( duplicate );
+ }
+ usersByOrg.remove( duplicate );
+ }
+
+ @Override
+ public Set<OrgUser> getOrgUsers(Org org) throws Exception {
+ return usersByOrg.get( org );
+ }
+
+ @Override
+ public void removeUserFromOrg(OrgUser user, Org org) throws Exception {
+
+ Set<OrgUser> orgUsers = usersByOrg.get( org );
+ orgUsers.remove( user );
+
+ Set<Org> usersOrgs = orgsByUser.get( user );
+ usersOrgs.remove( org );
+ }
+
+ @Override
+ public void addUserToOrg(OrgUser user, Org org) throws Exception {
+
+ Set<Org> usersOrgs = orgsByUser.get( user );
+ usersOrgs.add( org );
+
+ Set<OrgUser> orgsUsers = usersByOrg.get( org );
+ orgsUsers.add( user );
+ }
+
+ @Override
+ public Set<UUID> getOrgApps(Org org) {
+ return appsByOrg.get( org );
+ }
+
+ @Override
+ public void removeAppFromOrg(UUID appId, Org org) throws Exception {
+ Set<UUID> apps = appsByOrg.get( org );
+ apps.remove( appId );
+ }
+
+ @Override
+ public void addAppToOrg(UUID appId, Org org) throws Exception {
+ Set<UUID> apps = appsByOrg.get( org );
+ apps.add(appId);
+ }
+
+ @Override
+ public void logDuplicates(Map<String, Set<Org>> duplicatesByName) {
+
+ for (String orgName : duplicatesByName.keySet()) {
+ Set<Org> orgs = duplicatesByName.get( orgName );
+ for (Org org : orgs) {
+ logger.info( "Duplicate org {}:{}", orgName, org.getId() );
+ }
+ }
+ }
+ }
+}
[2/7] usergrid git commit: Add double protection for dryrun mode,
and some more logging.
Posted by mr...@apache.org.
Add double protection for dryrun mode, and some more logging.
Project: http://git-wip-us.apache.org/repos/asf/usergrid/repo
Commit: http://git-wip-us.apache.org/repos/asf/usergrid/commit/de254f0a
Tree: http://git-wip-us.apache.org/repos/asf/usergrid/tree/de254f0a
Diff: http://git-wip-us.apache.org/repos/asf/usergrid/diff/de254f0a
Branch: refs/heads/1.x
Commit: de254f0acce9f69842f04be3fc0904dae37f54a4
Parents: 674532f
Author: Dave Johnson <sn...@apache.org>
Authored: Fri Dec 11 14:54:26 2015 -0500
Committer: Dave Johnson <sn...@apache.org>
Committed: Fri Dec 11 14:54:26 2015 -0500
----------------------------------------------------------------------
.../usergrid/tools/DuplicateOrgRepair.java | 102 +++++++++++++++----
.../usergrid/tools/DuplicateOrgRepairTest.java | 6 ++
2 files changed, 87 insertions(+), 21 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/usergrid/blob/de254f0a/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateOrgRepair.java
----------------------------------------------------------------------
diff --git a/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateOrgRepair.java b/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateOrgRepair.java
index bc4acb5..4b5e391 100644
--- a/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateOrgRepair.java
+++ b/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateOrgRepair.java
@@ -18,7 +18,6 @@
package org.apache.usergrid.tools;
import com.google.common.collect.BiMap;
-import com.google.common.collect.Sets;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
@@ -51,7 +50,7 @@ import static org.apache.usergrid.tools.DuplicateOrgInterface.OrgUser;
*/
public class DuplicateOrgRepair extends ToolBase {
- DuplicateOrgInterface manager = new Manager();
+ DuplicateOrgInterface manager;
Map<String, Set<Org>> orgsByName = new HashMap<String, Set<Org>>();
@@ -68,6 +67,8 @@ public class DuplicateOrgRepair extends ToolBase {
static final String DRYRUN_ARG_NAME = "dryrun";
static boolean dryRun = false;
+
+ static boolean testing = false;
@Override
@@ -94,13 +95,10 @@ public class DuplicateOrgRepair extends ToolBase {
@Override
public void runTool(CommandLine line) throws Exception {
- logger.info( "DuplicateOrgRepair tool starting up..." );
startSpring();
setVerbose( line );
- dryRun = Boolean.parseBoolean( line.getOptionValue( DRYRUN_ARG_NAME ));
-
if (StringUtils.isNotEmpty( line.getOptionValue( THREADS_ARG_NAME ) )) {
try {
threadCount = Integer.parseInt( line.getOptionValue( THREADS_ARG_NAME ) );
@@ -110,15 +108,27 @@ public class DuplicateOrgRepair extends ToolBase {
}
}
- buildOrgMaps();
+ dryRun = Boolean.parseBoolean( line.getOptionValue( DRYRUN_ARG_NAME ));
+
+ if ( dryRun && !testing ) {
+ manager = new DryRunManager();
+ } else {
+ manager = new RepairManager();
+ }
+ logger.info( "DuplicateOrgRepair tool starting up... manager: " + manager.getClass().getSimpleName() );
+
+ buildOrgMaps();
+
augmentUserOrgsMap();
+ manager.logDuplicates( duplicatesByName );
+
mergeDuplicateOrgs();
-
+
removeDuplicateOrgs();
- logger.info( "DuplicateOrgRepair work is done." );
+ logger.info( "DuplicateOrgRepair work is done!");
}
@@ -158,10 +168,14 @@ public class DuplicateOrgRepair extends ToolBase {
}
} catch (Exception e) {
logger.error("Error getting users for org {}:{}", org.getName(), org.getId());
+ logger.error("Stack trace is: ", e);
}
}
+
} ).toBlocking().lastOrDefault( null );
+
+ logger.info( "DuplicateOrgRepair tool built org maps");
}
@@ -179,6 +193,9 @@ public class DuplicateOrgRepair extends ToolBase {
try {
Set<Org> connectedToOrgs = manager.getUsersOrgs(user);
Set<Org> usersOrgs = orgsByUser.get(user);
+ if ( usersOrgs == null ) {
+ usersOrgs = new HashSet<Org>();
+ }
for ( Org org : connectedToOrgs ) {
if (!usersOrgs.contains(org)) {
usersOrgs.add(org);
@@ -187,9 +204,12 @@ public class DuplicateOrgRepair extends ToolBase {
} catch (Exception e) {
logger.error("Error getting orgs for user {}:{}", user.getName(), user.getId());
+ logger.error("Stack trace is: ", e);
}
}
} ).subscribeOn( scheduler ).toBlocking().lastOrDefault( null );
+
+ logger.info( "DuplicateOrgRepair augmented user orgs map");
}
@@ -216,10 +236,10 @@ public class DuplicateOrgRepair extends ToolBase {
args = new Object[] {
user.getName(), user.getId(), org.getName(), org.getId()};
logger.info( "Would remove user {}:{} org {}:{}", args);
- continue;
- }
- manager.addUserToOrg( user, bestOrg );
- manager.removeUserFromOrg( user, org );
+ } else {
+ manager.addUserToOrg( user, bestOrg );
+ manager.removeUserFromOrg( user, org );
+ }
}
Set<UUID> orgApps = new HashSet<UUID>( manager.getOrgApps( org ));
@@ -232,14 +252,16 @@ public class DuplicateOrgRepair extends ToolBase {
args = new Object[] {
appId, org.getName(), org.getId()};
logger.info( "Would remove app {} org {}:{}", args);
- continue;
- }
- manager.addAppToOrg( appId, bestOrg );
- manager.removeAppFromOrg( appId, org );
+ } else {
+ manager.addAppToOrg( appId, bestOrg );
+ manager.removeAppFromOrg( appId, org );
+ }
}
}
}
}
+
+ logger.info( "DuplicateOrgRepair merged duplicate orgs");
}
@@ -261,6 +283,7 @@ public class DuplicateOrgRepair extends ToolBase {
}
}
}
+ logger.info( "DuplicateOrgRepair renamed/removed duplicate orgs");
}
@@ -276,9 +299,11 @@ public class DuplicateOrgRepair extends ToolBase {
}
return oldest;
}
-
- class Manager implements DuplicateOrgInterface {
+
+
+
+ class RepairManager implements DuplicateOrgInterface {
private boolean dryRun = true;
@@ -291,6 +316,8 @@ public class DuplicateOrgRepair extends ToolBase {
public void call(Subscriber<? super Org> subscriber) {
subscriber.onStart();
try {
+ int count = 0;
+
Query query = new Query();
query.setLimit( MAX_ENTITY_FETCH );
query.setResultsLevel( Results.Level.ALL_PROPERTIES );
@@ -308,6 +335,10 @@ public class DuplicateOrgRepair extends ToolBase {
subscriber.onNext( org );
+ if ( count++ % 1000 == 0 ) {
+ logger.info("Emitted {} orgs", count );
+ }
+
// logger.info( "org: {}, \"{}\", {}", new Object[]{
// orgEntity.getProperty( "path" ),
// orgEntity.getUuid(),
@@ -337,6 +368,8 @@ public class DuplicateOrgRepair extends ToolBase {
public void call(Subscriber<? super OrgUser> subscriber) {
subscriber.onStart();
try {
+ int count = 0;
+
Query query = new Query();
query.setLimit( MAX_ENTITY_FETCH );
query.setResultsLevel( Results.Level.ALL_PROPERTIES );
@@ -352,7 +385,11 @@ public class DuplicateOrgRepair extends ToolBase {
orgUser.sourceValue = entity;
subscriber.onNext( orgUser );
-
+
+ if ( count++ % 1000 == 0 ) {
+ logger.info("Emitted {} users", count );
+ }
+
// logger.info( "org: {}, \"{}\", {}", new Object[]{
// entity.getProperty( "path" ),
// entity.getUuid(),
@@ -401,9 +438,7 @@ public class DuplicateOrgRepair extends ToolBase {
@Override
public void removeOrg(Org keeper, Org duplicate) throws Exception {
-
// we don't have a remove org API so rename org so that it is no longer a duplicate
-
OrganizationInfo orgInfo = managementService.getOrganizationByUuid( duplicate.getId() );
orgInfo.setName( "dup_" + keeper.getId() + "_" + RandomStringUtils.randomAlphanumeric(10) );
managementService.updateOrganization( orgInfo );
@@ -491,4 +526,29 @@ public class DuplicateOrgRepair extends ToolBase {
}
}
+
+
+ class DryRunManager extends RepairManager {
+
+ @Override
+ public void removeUserFromOrg(OrgUser user, Org org) throws Exception {
+ }
+
+ @Override
+ public void addUserToOrg(OrgUser user, Org org) throws Exception {
+ }
+
+ @Override
+ public void addAppToOrg(UUID appId, Org org) throws Exception {
+ }
+
+ @Override
+ public void removeAppFromOrg(UUID appId, Org org) throws Exception {
+ }
+
+ @Override
+ public void removeOrg(Org keeper, Org duplicate) throws Exception {
+ }
+ }
+
}
http://git-wip-us.apache.org/repos/asf/usergrid/blob/de254f0a/stack/tools/src/test/java/org/apache/usergrid/tools/DuplicateOrgRepairTest.java
----------------------------------------------------------------------
diff --git a/stack/tools/src/test/java/org/apache/usergrid/tools/DuplicateOrgRepairTest.java b/stack/tools/src/test/java/org/apache/usergrid/tools/DuplicateOrgRepairTest.java
index ac95748..4c92761 100644
--- a/stack/tools/src/test/java/org/apache/usergrid/tools/DuplicateOrgRepairTest.java
+++ b/stack/tools/src/test/java/org/apache/usergrid/tools/DuplicateOrgRepairTest.java
@@ -57,6 +57,8 @@ public class DuplicateOrgRepairTest {
int numOrgs = 10; // create 10 orgs and a dup for each
final DuplicateOrgRepair dor = new DuplicateOrgRepair();
+ dor.testing = true;
+
dor.manager = new Manager( numOrgs );
assertEquals( "must start with dups",
@@ -92,6 +94,7 @@ public class DuplicateOrgRepairTest {
int numOrgs = 10; // create 10 orgs and a dup for each
DuplicateOrgRepair dor = new DuplicateOrgRepair();
+ dor.testing = true;
dor.manager = new Manager( numOrgs );
assertEquals( "must start with dups",
@@ -131,6 +134,7 @@ public class DuplicateOrgRepairTest {
orgOwnerInfo1.getOwner(), orgOwnerInfo2.getOrganization(), false );
DuplicateOrgRepair dor = new DuplicateOrgRepair();
+ dor.testing = true;
dor.startTool( new String[] {}, false ); // false means do not call System.exit()
@@ -156,6 +160,7 @@ public class DuplicateOrgRepairTest {
"user_" + random2 + "@example.com", "password" );
DuplicateOrgRepair dor = new DuplicateOrgRepair();
+ dor.testing = true;
// start the tool so thaht Spring, Cassandra, etc/ gets initialized
dor.startTool( new String[] { "-dryrun", "true" }, false ); // false means do not call System.exit()
@@ -216,6 +221,7 @@ public class DuplicateOrgRepairTest {
orgOwnerInfo2.getOrganization().getUuid(), "app_" + RandomStringUtils.randomAlphanumeric( 10 ));
DuplicateOrgRepair dor = new DuplicateOrgRepair();
+ dor.testing = true;
// start the tool so that Spring, Cassandra, etc/ gets initialized
dor.startTool( new String[] { "-dryrun", "true" }, false ); // false means do not call System.exit()
[6/7] usergrid git commit: Improvements to option handling,
test improvements and remove old dup-repair tool.
Posted by mr...@apache.org.
Improvements to option handling, test improvements and remove old dup-repair tool.
Project: http://git-wip-us.apache.org/repos/asf/usergrid/repo
Commit: http://git-wip-us.apache.org/repos/asf/usergrid/commit/3ab0c4fb
Tree: http://git-wip-us.apache.org/repos/asf/usergrid/tree/3ab0c4fb
Diff: http://git-wip-us.apache.org/repos/asf/usergrid/diff/3ab0c4fb
Branch: refs/heads/1.x
Commit: 3ab0c4fb084dd1153c04fe989603ec0e0d73ee38
Parents: 91e8fe8
Author: Dave Johnson <sn...@apache.org>
Authored: Thu Dec 17 16:27:05 2015 -0500
Committer: Dave Johnson <sn...@apache.org>
Committed: Thu Dec 17 16:27:05 2015 -0500
----------------------------------------------------------------------
.../org/apache/usergrid/tools/DupOrgRepair.java | 267 -------------------
.../usergrid/tools/DuplicateOrgRepair.java | 33 ++-
.../usergrid/tools/DuplicateOrgRepairTest.java | 63 +++--
3 files changed, 58 insertions(+), 305 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/usergrid/blob/3ab0c4fb/stack/tools/src/main/java/org/apache/usergrid/tools/DupOrgRepair.java
----------------------------------------------------------------------
diff --git a/stack/tools/src/main/java/org/apache/usergrid/tools/DupOrgRepair.java b/stack/tools/src/main/java/org/apache/usergrid/tools/DupOrgRepair.java
deleted file mode 100644
index d6a00b6..0000000
--- a/stack/tools/src/main/java/org/apache/usergrid/tools/DupOrgRepair.java
+++ /dev/null
@@ -1,267 +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.Collection;
-import java.util.Map;
-import java.util.Map.Entry;
-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.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;
-
-
-/**
- * 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 DupOrgRepair extends ExportingToolBase {
-
- /**
- *
- */
- private static final int PAGE_SIZE = 100;
-
- private static final Logger logger = LoggerFactory.getLogger( DupOrgRepair.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" );
-
- createDir( outputDir );
-
- 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> orgs = HashMultimap.create();
-
- do {
-
- r = em.searchCollection( app, "groups", query );
-
- for ( Entity entity : r.getEntities() ) {
- String name = entity.getProperty( "path" ).toString().toLowerCase();
- orgs.put( name, 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 name : orgs.keySet() ) {
- Collection<UUID> ids = orgs.get( name );
-
- if ( ids.size() > 1 ) {
- logger.warn( "Found multiple orgs with the name {}", name );
-
- // look this up the same way the REST tier does. This way we will always
- // map the same way and the user will not notice a background merge
- OrganizationInfo orgInfo = managementService.getOrganizationByName( name );
-
- UUID targetOrgId = orgInfo.getUuid();
-
- ids.remove( targetOrgId );
-
- for ( UUID sourceId : ids ) {
- mergeOrganizations( outputDir, sourceId, targetOrgId );
- }
- }
- }
-
- logger.info( "Merge complete" );
- }
-
-
- /**
- * Merge the source orgId into the targetId in the following way.
- * <p/>
- * 1) link all admins from the source org to the target org 2) link all apps from the source org to the target or 3)
- * delete the target org
- */
- @SuppressWarnings("unchecked")
- private void mergeOrganizations( String outputDir, UUID sourceOrgId, UUID targetOrgId ) throws Exception {
-
- OrganizationInfo sourceOrgInfo = managementService.getOrganizationByUuid( sourceOrgId );
-
- Map<String, Object> sourceOrg = managementService.getOrganizationData( sourceOrgInfo );
-
- OrganizationInfo targetOrgInfo = managementService.getOrganizationByUuid( targetOrgId );
-
- Map<String, Object> targetOrg = managementService.getOrganizationData( targetOrgInfo );
-
- // Dump the output on these two orgs
- FileWriter file =
- new FileWriter( String.format( "%s/%s.%s.orig", outputDir, sourceOrgInfo.getName(), sourceOrgId ) );
-
- file.write( JsonUtils.mapToFormattedJsonString( sourceOrg ) );
-
- file.write( "\n\n" );
-
- file.write( JsonUtils.mapToFormattedJsonString( targetOrg ) );
-
- file.flush();
- file.close();
-
- // BiMap<UUID, String> targetApps =
- // managementService.getApplicationsForOrganization(targetOrgId);
-
- // now perform the merge
-
- // add all the admins
- Map<String, UserInfo> admins = ( Map<String, UserInfo> ) sourceOrg.get( "users" );
-
- for ( Entry<String, UserInfo> adminEntry : admins.entrySet() ) {
- UserInfo admin = adminEntry.getValue();
-
- logger.info( "adding admin with uuid {} and email {} to org with name {} and uuid {}", new Object[] {
- admin.getUuid(), admin.getEmail(), targetOrgInfo.getName(), targetOrgInfo.getUuid()
- } );
-
- // copy the admins over
- managementService.addAdminUserToOrganization( admin, targetOrgInfo, false );
- }
-
- // get the root entity manager
- EntityManager em = emf.getEntityManager( CassandraService.MANAGEMENT_APPLICATION_ID );
-
- // Add the apps to the org
- Map<String, UUID> sourceApps = ( Map<String, UUID> ) sourceOrg.get( "applications" );
-
- Map<String, UUID> targetApps = ( Map<String, UUID> ) targetOrg.get( "applications" );
-
- for ( Entry<String, UUID> app : sourceApps.entrySet() ) {
-
- // we have colliding app names
- if ( targetApps.get( app.getKey() ) != null ) {
-
- // already added, skip it
- if ( app.getValue().equals( targetApps.get( app.getKey() ) ) ) {
- continue;
- }
-
- // check to see if this orgname/appname lookup returns the app we're
- // about to re-assign. If it does NOT, then we need to rename this app
- // before performing the link.
- UUID appIdToKeep = emf.lookupApplication( app.getKey() );
-
- UUID appIdToChange =
- appIdToKeep.equals( app.getValue() ) ? targetApps.get( app.getKey() ) : app.getValue();
-
- // get the existing target entity
- Entity appEntity = em.get( appIdToChange );
-
- if ( appEntity != null ) {
-
- String oldName = appEntity.getProperty( "name" ).toString();
- String newName = oldName + appEntity.getUuid();
-
- //force the property to be updated
- em.setProperty( appEntity, "name", newName, true );
-
- logger.info( "Renamed app from {} to {}", oldName, newName );
- }
- }
-
- logger.info( "Adding application with name {} and id {} to organization with uuid {}", new Object[] {
- app.getKey(), app.getValue(), targetOrgId
- } );
- managementService.addApplicationToOrganization( targetOrgId, app.getValue() );
- }
-
- // now delete the original org
-
- logger.info( "Deleting org with the name {} and uuid {}", sourceOrgInfo.getName(), sourceOrgInfo.getUuid() );
-
- // delete the source org
- em.delete( new SimpleEntityRef( "group", sourceOrgId ) );
-
- // re-dump the target from the cassandra stat
- targetOrgInfo = managementService.getOrganizationByUuid( targetOrgId );
-
- targetOrg = managementService.getOrganizationData( targetOrgInfo );
-
- file = new FileWriter( String.format( "%s/%s.%s.new", outputDir, targetOrgInfo.getName(), targetOrgId ) );
-
- file.write( JsonUtils.mapToFormattedJsonString( targetOrg ) );
-
- file.flush();
- file.close();
- }
-}
http://git-wip-us.apache.org/repos/asf/usergrid/blob/3ab0c4fb/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateOrgRepair.java
----------------------------------------------------------------------
diff --git a/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateOrgRepair.java b/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateOrgRepair.java
index 6f9e301..c703305 100644
--- a/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateOrgRepair.java
+++ b/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateOrgRepair.java
@@ -115,24 +115,29 @@ public class DuplicateOrgRepair extends ToolBase {
UUID org1uuid = null;
UUID org2uuid = null;
-
- if ( StringUtils.isNotEmpty( line.getOptionValue( ORG1_ID) )) {
- if ( StringUtils.isNotEmpty( line.getOptionValue( ORG2_ID) )) {
- try {
- org1uuid = UUID.fromString( line.getOptionValue( ORG1_ID ) );
- org2uuid = UUID.fromString( line.getOptionValue( ORG2_ID ) );
- } catch (Exception e) {
- logger.error("{} and {} must be specified as UUIDs", ORG1_ID, ORG2_ID);
- return;
- }
-
-
- } else {
- logger.error("- if {} is specified you must also specify {} and vice-versa", ORG1_ID, ORG2_ID);
+ String org1string = line.getOptionValue( ORG1_ID );
+ String org2string = line.getOptionValue( ORG2_ID );
+
+ if ( org1string != null && org2string == null ) {
+ logger.error("- if {} is specified you must also specify {} and vice-versa", ORG1_ID, ORG2_ID);
+ return;
+
+ } else if ( org2string != null && org1string == null ) {
+ logger.error("- if {} is specified you must also specify {} and vice-versa", ORG2_ID, ORG1_ID);
+ return;
+
+ } else if ( org1string != null && org2string != null ) {
+
+ try {
+ org1uuid = UUID.fromString( org1string );
+ org2uuid = UUID.fromString( org2string );
+ } catch (Exception e) {
+ logger.error("{} and {} must be specified as UUIDs", ORG1_ID, ORG2_ID);
return;
}
}
+
if (StringUtils.isNotEmpty( line.getOptionValue( THREADS_ARG_NAME ) )) {
try {
threadCount = Integer.parseInt( line.getOptionValue( THREADS_ARG_NAME ) );
http://git-wip-us.apache.org/repos/asf/usergrid/blob/3ab0c4fb/stack/tools/src/test/java/org/apache/usergrid/tools/DuplicateOrgRepairTest.java
----------------------------------------------------------------------
diff --git a/stack/tools/src/test/java/org/apache/usergrid/tools/DuplicateOrgRepairTest.java b/stack/tools/src/test/java/org/apache/usergrid/tools/DuplicateOrgRepairTest.java
index daf40d3..8726a33 100644
--- a/stack/tools/src/test/java/org/apache/usergrid/tools/DuplicateOrgRepairTest.java
+++ b/stack/tools/src/test/java/org/apache/usergrid/tools/DuplicateOrgRepairTest.java
@@ -67,47 +67,62 @@ public class DuplicateOrgRepairTest {
assertEquals( "must remove dups",
numOrgs, (long)dor.manager.getOrgs().count().toBlocking().single());
-
- dor.manager.getOrgs().doOnNext( new Action1<Org>() {
- @Override
- public void call(Org org) {
- try {
- assertEquals("remaining orgs should have right number of users",
- 3, dor.manager.getOrgUsers(org).size());
- assertEquals("remaining orgs should have right number of apps",
- 3, dor.manager.getOrgApps(org).size());
-
- } catch (Exception e) {
- logger.error("Error counting apps or users: " + e.getMessage(), e);
- fail("Error counting apps or users");
- }
- }
- }).toBlocking().lastOrDefault( null );
+ checkOrgsDeduped( dor );
}
@org.junit.Test
- public void testMockWithOneDup() throws Exception {
+ public void testMockWithOneDupoDryRun() throws Exception {
int numOrgs = 1; // create 1 org and a dup
- final DuplicateOrgRepair dor = new DuplicateOrgRepair();
+ DuplicateOrgRepair dor = new DuplicateOrgRepair();
dor.testing = true;
-
dor.manager = new Manager( numOrgs );
assertEquals( "must start with dups",
- 2 * numOrgs, (long)dor.manager.getOrgs().count().toBlocking().single());
+ 2 * numOrgs, (long) dor.manager.getOrgs().count().toBlocking().single() );
+
+ Iterator<Org> orgIter = ((Manager) dor.manager).usersByOrg.keySet().iterator();
+ Org org1 = orgIter.next();
+ Org org2 = orgIter.next();
+ dor.startTool( new String[]{
+ "-org1", org1.getId() + "",
+ "-org2", org2.getId() + "",
+ "-dryrun", "true"
+ }, false ); // false means do not call System.exit()
+ assertEquals( "dry-run should not remove dups",
+ 2 * numOrgs, (long) dor.manager.getOrgs().count().toBlocking().single() );
+ }
+
+
+ @org.junit.Test
+ public void testMockWithOneDup() throws Exception {
+
+ int numOrgs = 1; // create 1 org and a dup
+
+ DuplicateOrgRepair dor = new DuplicateOrgRepair();
+ dor.testing = true;
+ dor.manager = new Manager( numOrgs );
+
+ Iterator<Org> orgIter = ((Manager)dor.manager).usersByOrg.keySet().iterator();
+ Org org1 = orgIter.next();
+ Org org2 = orgIter.next();
dor.startTool( new String[] {
- "org1", ((Manager)dor.manager).usersByOrg.keySet().iterator().next().getId()+"",
- "org2", ((Manager)dor.manager).usersByOrg.keySet().iterator().next().getId()+""
+ "-org1", org1.getId()+"",
+ "-org2", org2.getId()+"",
}, false ); // false means do not call System.exit()
assertEquals( "must remove dups",
numOrgs, (long)dor.manager.getOrgs().count().toBlocking().single());
+ checkOrgsDeduped( dor );
+ }
+
+
+ private void checkOrgsDeduped(final DuplicateOrgRepair dor) throws Exception {
dor.manager.getOrgs().doOnNext( new Action1<Org>() {
@Override
public void call(Org org) {
@@ -125,8 +140,8 @@ public class DuplicateOrgRepairTest {
}
}).toBlocking().lastOrDefault( null );
}
-
-
+
+
@org.junit.Test
public void testMockWithDupsDryRun() throws Exception {
[3/7] usergrid git commit: Fix tests broken by previous commit.
Posted by mr...@apache.org.
Fix tests broken by previous commit.
Project: http://git-wip-us.apache.org/repos/asf/usergrid/repo
Commit: http://git-wip-us.apache.org/repos/asf/usergrid/commit/0e6f4c99
Tree: http://git-wip-us.apache.org/repos/asf/usergrid/tree/0e6f4c99
Diff: http://git-wip-us.apache.org/repos/asf/usergrid/diff/0e6f4c99
Branch: refs/heads/1.x
Commit: 0e6f4c99af2a40ceb4fc06532c6a8c9601282f21
Parents: de254f0
Author: Dave Johnson <sn...@apache.org>
Authored: Mon Dec 14 17:22:03 2015 -0500
Committer: Dave Johnson <sn...@apache.org>
Committed: Mon Dec 14 17:22:03 2015 -0500
----------------------------------------------------------------------
.../usergrid/tools/DuplicateOrgRepair.java | 34 +++++++------
.../usergrid/tools/DuplicateOrgRepairTest.java | 13 ++---
.../test/resources/usergrid-test-context.xml | 52 ++++++++++++++++++++
3 files changed, 78 insertions(+), 21 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/usergrid/blob/0e6f4c99/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateOrgRepair.java
----------------------------------------------------------------------
diff --git a/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateOrgRepair.java b/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateOrgRepair.java
index 4b5e391..1795af1 100644
--- a/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateOrgRepair.java
+++ b/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateOrgRepair.java
@@ -23,6 +23,7 @@ import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.commons.lang3.StringUtils;
import org.apache.usergrid.management.OrganizationInfo;
import org.apache.usergrid.management.UserInfo;
import org.apache.usergrid.persistence.Entity;
@@ -31,7 +32,6 @@ import org.apache.usergrid.persistence.Query;
import org.apache.usergrid.persistence.Results;
import org.apache.usergrid.persistence.cassandra.CassandraService;
import org.apache.usergrid.persistence.entities.Group;
-import org.apache.usergrid.utils.StringUtils;
import rx.Observable;
import rx.Scheduler;
import rx.Subscriber;
@@ -50,7 +50,7 @@ import static org.apache.usergrid.tools.DuplicateOrgInterface.OrgUser;
*/
public class DuplicateOrgRepair extends ToolBase {
- DuplicateOrgInterface manager;
+ DuplicateOrgInterface manager = null;
Map<String, Set<Org>> orgsByName = new HashMap<String, Set<Org>>();
@@ -62,14 +62,12 @@ public class DuplicateOrgRepair extends ToolBase {
static final String THREADS_ARG_NAME = "threads";
- static int threadCount = 5;
+ int threadCount = 5;
static final String DRYRUN_ARG_NAME = "dryrun";
- static boolean dryRun = false;
+ boolean dryRun = false;
- static boolean testing = false;
-
@Override
@SuppressWarnings("static-access")
@@ -95,7 +93,6 @@ public class DuplicateOrgRepair extends ToolBase {
@Override
public void runTool(CommandLine line) throws Exception {
-
startSpring();
setVerbose( line );
@@ -108,13 +105,17 @@ public class DuplicateOrgRepair extends ToolBase {
}
}
- dryRun = Boolean.parseBoolean( line.getOptionValue( DRYRUN_ARG_NAME ));
-
- if ( dryRun && !testing ) {
- manager = new DryRunManager();
- } else {
- manager = new RepairManager();
+ 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 DryRunManager();
+ } else {
+ manager = new RepairManager();
+ }
+ }
logger.info( "DuplicateOrgRepair tool starting up... manager: " + manager.getClass().getSimpleName() );
@@ -130,6 +131,11 @@ public class DuplicateOrgRepair extends ToolBase {
logger.info( "DuplicateOrgRepair work is done!");
}
+
+
+ public RepairManager createNewRepairManager() {
+ return new RepairManager();
+ }
/**
@@ -300,8 +306,6 @@ public class DuplicateOrgRepair extends ToolBase {
return oldest;
}
-
-
class RepairManager implements DuplicateOrgInterface {
http://git-wip-us.apache.org/repos/asf/usergrid/blob/0e6f4c99/stack/tools/src/test/java/org/apache/usergrid/tools/DuplicateOrgRepairTest.java
----------------------------------------------------------------------
diff --git a/stack/tools/src/test/java/org/apache/usergrid/tools/DuplicateOrgRepairTest.java b/stack/tools/src/test/java/org/apache/usergrid/tools/DuplicateOrgRepairTest.java
index 4c92761..f871e50 100644
--- a/stack/tools/src/test/java/org/apache/usergrid/tools/DuplicateOrgRepairTest.java
+++ b/stack/tools/src/test/java/org/apache/usergrid/tools/DuplicateOrgRepairTest.java
@@ -57,7 +57,6 @@ public class DuplicateOrgRepairTest {
int numOrgs = 10; // create 10 orgs and a dup for each
final DuplicateOrgRepair dor = new DuplicateOrgRepair();
- dor.testing = true;
dor.manager = new Manager( numOrgs );
@@ -94,7 +93,6 @@ public class DuplicateOrgRepairTest {
int numOrgs = 10; // create 10 orgs and a dup for each
DuplicateOrgRepair dor = new DuplicateOrgRepair();
- dor.testing = true;
dor.manager = new Manager( numOrgs );
assertEquals( "must start with dups",
@@ -134,7 +132,6 @@ public class DuplicateOrgRepairTest {
orgOwnerInfo1.getOwner(), orgOwnerInfo2.getOrganization(), false );
DuplicateOrgRepair dor = new DuplicateOrgRepair();
- dor.testing = true;
dor.startTool( new String[] {}, false ); // false means do not call System.exit()
@@ -160,7 +157,7 @@ public class DuplicateOrgRepairTest {
"user_" + random2 + "@example.com", "password" );
DuplicateOrgRepair dor = new DuplicateOrgRepair();
- dor.testing = true;
+ dor.manager = dor.createNewRepairManager(); // test the real manager
// start the tool so thaht Spring, Cassandra, etc/ gets initialized
dor.startTool( new String[] { "-dryrun", "true" }, false ); // false means do not call System.exit()
@@ -211,17 +208,21 @@ public class DuplicateOrgRepairTest {
"org_" + random2, "user_" + random2, "user_" + random2,
"user_" + random2 + "@example.com", "password" );
+ // give org1 two apps
+
ApplicationInfo app11 = setup.getMgmtSvc().createApplication(
orgOwnerInfo1.getOrganization().getUuid(), "app_" + RandomStringUtils.randomAlphanumeric( 10 ) );
ApplicationInfo app12= setup.getMgmtSvc().createApplication(
orgOwnerInfo1.getOrganization().getUuid(), "app_" + RandomStringUtils.randomAlphanumeric( 10 ));
+ // give org2 one app
+
ApplicationInfo app21 = setup.getMgmtSvc().createApplication(
orgOwnerInfo2.getOrganization().getUuid(), "app_" + RandomStringUtils.randomAlphanumeric( 10 ));
DuplicateOrgRepair dor = new DuplicateOrgRepair();
- dor.testing = true;
+ 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()
@@ -248,7 +249,7 @@ public class DuplicateOrgRepairTest {
/**
- * Mock manager implementation for testing.
+ * Mock manager implementation for mockTesting.
*/
class Manager implements DuplicateOrgInterface {
http://git-wip-us.apache.org/repos/asf/usergrid/blob/0e6f4c99/stack/tools/src/test/resources/usergrid-test-context.xml
----------------------------------------------------------------------
diff --git a/stack/tools/src/test/resources/usergrid-test-context.xml b/stack/tools/src/test/resources/usergrid-test-context.xml
new file mode 100644
index 0000000..f07b87e
--- /dev/null
+++ b/stack/tools/src/test/resources/usergrid-test-context.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:util="http://www.springframework.org/schema/util"
+ xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
+ xmlns:hz="http://www.hazelcast.com/schema/config" xmlns:aop="http://www.springframework.org/schema/aop"
+ xsi:schemaLocation="
+ http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
+ http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
+ http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
+ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
+
+ <bean id="properties"
+ class="org.springframework.beans.factory.config.PropertiesFactoryBean">
+ <property name="singleton" value="true" />
+ <property name="ignoreResourceNotFound" value="true" />
+ <property name="locations">
+ <list>
+ <value>classpath:/usergrid-default.properties</value>
+ </list>
+ </property>
+ </bean>
+
+ <import resource="classpath:/toolsApplicationContext.xml"/>
+
+ <bean id="setup" class="org.apache.usergrid.persistence.cassandra.Setup">
+ <constructor-arg ref="entityManagerFactory"/>
+ <constructor-arg ref="cassandraService"/>
+ </bean>
+
+ <bean id="coreManager" class="org.apache.usergrid.persistence.CoreSchemaManager">
+ <constructor-arg ref="setup"/>
+ <constructor-arg ref="cassandraCluster"/>
+ </bean>
+
+</beans>
[7/7] usergrid git commit: Merge commit 'refs/pull/448/head' of
github.com:apache/usergrid into 1.x
Posted by mr...@apache.org.
Merge commit 'refs/pull/448/head' of github.com:apache/usergrid into 1.x
Project: http://git-wip-us.apache.org/repos/asf/usergrid/repo
Commit: http://git-wip-us.apache.org/repos/asf/usergrid/commit/69eeb918
Tree: http://git-wip-us.apache.org/repos/asf/usergrid/tree/69eeb918
Diff: http://git-wip-us.apache.org/repos/asf/usergrid/diff/69eeb918
Branch: refs/heads/1.x
Commit: 69eeb9187f46f2d314b746f6ee6c30669650539b
Parents: ccf4e42 3ab0c4f
Author: Michael Russo <mi...@gmail.com>
Authored: Thu Dec 17 14:14:09 2015 -0800
Committer: Michael Russo <mi...@gmail.com>
Committed: Thu Dec 17 14:14:09 2015 -0800
----------------------------------------------------------------------
.../usergrid/management/ManagementService.java | 4 +-
.../cassandra/ManagementServiceImpl.java | 28 +-
.../org/apache/usergrid/tools/DupOrgRepair.java | 267 --------
.../usergrid/tools/DuplicateOrgInterface.java | 112 ++++
.../usergrid/tools/DuplicateOrgRepair.java | 660 +++++++++++++++++++
.../usergrid/tools/DuplicateOrgRepairTest.java | 472 +++++++++++++
.../test/resources/usergrid-test-context.xml | 52 ++
7 files changed, 1324 insertions(+), 271 deletions(-)
----------------------------------------------------------------------
[5/7] usergrid git commit: Correctly match option names to variable
names.
Posted by mr...@apache.org.
Correctly match option names to variable names.
Project: http://git-wip-us.apache.org/repos/asf/usergrid/repo
Commit: http://git-wip-us.apache.org/repos/asf/usergrid/commit/91e8fe85
Tree: http://git-wip-us.apache.org/repos/asf/usergrid/tree/91e8fe85
Diff: http://git-wip-us.apache.org/repos/asf/usergrid/diff/91e8fe85
Branch: refs/heads/1.x
Commit: 91e8fe85eeab898ce1f7e640412e08cef1742814
Parents: 33a74e8
Author: Dave Johnson <sn...@apache.org>
Authored: Tue Dec 15 10:45:24 2015 -0500
Committer: Dave Johnson <sn...@apache.org>
Committed: Tue Dec 15 10:45:24 2015 -0500
----------------------------------------------------------------------
.../main/java/org/apache/usergrid/tools/DuplicateOrgRepair.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/usergrid/blob/91e8fe85/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateOrgRepair.java
----------------------------------------------------------------------
diff --git a/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateOrgRepair.java b/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateOrgRepair.java
index 572c9b4..6f9e301 100644
--- a/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateOrgRepair.java
+++ b/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateOrgRepair.java
@@ -67,9 +67,9 @@ public class DuplicateOrgRepair extends ToolBase {
boolean dryRun = false;
- static final String ORG1_ID = "org2";
+ static final String ORG1_ID = "org1";
- static final String ORG2_ID = "org1";
+ static final String ORG2_ID = "org2";
boolean testing = false;
[4/7] usergrid git commit: Add org1 and org2 options so a user can
ask that two same-named orgs be merged.
Posted by mr...@apache.org.
Add org1 and org2 options so a user can ask that two same-named orgs be merged.
Project: http://git-wip-us.apache.org/repos/asf/usergrid/repo
Commit: http://git-wip-us.apache.org/repos/asf/usergrid/commit/33a74e82
Tree: http://git-wip-us.apache.org/repos/asf/usergrid/tree/33a74e82
Diff: http://git-wip-us.apache.org/repos/asf/usergrid/diff/33a74e82
Branch: refs/heads/1.x
Commit: 33a74e822d78c39aa13a1084b79b0a29ae3614ff
Parents: 0e6f4c9
Author: Dave Johnson <sn...@apache.org>
Authored: Mon Dec 14 17:26:32 2015 -0500
Committer: Dave Johnson <sn...@apache.org>
Committed: Mon Dec 14 17:26:32 2015 -0500
----------------------------------------------------------------------
.../usergrid/tools/DuplicateOrgInterface.java | 4 +-
.../usergrid/tools/DuplicateOrgRepair.java | 113 +++++++++++++++++--
.../usergrid/tools/DuplicateOrgRepairTest.java | 50 ++++++++
3 files changed, 158 insertions(+), 9 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/usergrid/blob/33a74e82/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateOrgInterface.java
----------------------------------------------------------------------
diff --git a/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateOrgInterface.java b/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateOrgInterface.java
index 596d55e..ab708c9 100644
--- a/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateOrgInterface.java
+++ b/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateOrgInterface.java
@@ -49,7 +49,9 @@ interface DuplicateOrgInterface {
void addAppToOrg( UUID appId, Org org ) throws Exception;
void logDuplicates(Map<String, Set<Org>> duplicatesByName);
-
+
+ Org getOrg(UUID keeperUuid) throws Exception;
+
class Org implements Comparable<Org> {
private UUID id;
private String name;
http://git-wip-us.apache.org/repos/asf/usergrid/blob/33a74e82/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateOrgRepair.java
----------------------------------------------------------------------
diff --git a/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateOrgRepair.java b/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateOrgRepair.java
index 1795af1..572c9b4 100644
--- a/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateOrgRepair.java
+++ b/stack/tools/src/main/java/org/apache/usergrid/tools/DuplicateOrgRepair.java
@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package org.apache.usergrid.tools;
import com.google.common.collect.BiMap;
@@ -63,11 +62,17 @@ public class DuplicateOrgRepair extends ToolBase {
static final String THREADS_ARG_NAME = "threads";
int threadCount = 5;
-
+
static final String DRYRUN_ARG_NAME = "dryrun";
boolean dryRun = false;
-
+
+ static final String ORG1_ID = "org2";
+
+ static final String ORG2_ID = "org1";
+
+ boolean testing = false;
+
@Override
@SuppressWarnings("static-access")
@@ -77,7 +82,7 @@ public class DuplicateOrgRepair extends ToolBase {
Option dryRunOption = OptionBuilder.hasArg()
.withType(Boolean.TRUE)
- .withDescription( "-" + DRYRUN_ARG_NAME + "true to print what tool would do and do not alter data.")
+ .withDescription( "-" + DRYRUN_ARG_NAME + " true to print what tool would do and do not alter data.")
.create( DRYRUN_ARG_NAME );
options.addOption( dryRunOption );
@@ -85,7 +90,19 @@ public class DuplicateOrgRepair extends ToolBase {
.withType(0)
.withDescription( "Write Threads -" + THREADS_ARG_NAME )
.create(THREADS_ARG_NAME);
- options.addOption( writeThreadsOption );
+ options.addOption( writeThreadsOption );
+
+ Option org1Option = OptionBuilder.hasArg()
+ .withType(0)
+ .withDescription( "Duplicate org #1 id -" + ORG1_ID)
+ .create(ORG1_ID);
+ options.addOption( org1Option );
+
+ Option org2Option = OptionBuilder.hasArg()
+ .withType(0)
+ .withDescription( "Duplicate org #2 id -" + ORG2_ID)
+ .create(ORG2_ID);
+ options.addOption( org2Option );
return options;
}
@@ -96,6 +113,26 @@ public class DuplicateOrgRepair extends ToolBase {
startSpring();
setVerbose( line );
+ UUID org1uuid = null;
+ UUID org2uuid = null;
+
+ if ( StringUtils.isNotEmpty( line.getOptionValue( ORG1_ID) )) {
+ if ( StringUtils.isNotEmpty( line.getOptionValue( ORG2_ID) )) {
+
+ try {
+ org1uuid = UUID.fromString( line.getOptionValue( ORG1_ID ) );
+ org2uuid = UUID.fromString( line.getOptionValue( ORG2_ID ) );
+ } catch (Exception e) {
+ logger.error("{} and {} must be specified as UUIDs", ORG1_ID, ORG2_ID);
+ return;
+ }
+
+
+ } else {
+ logger.error("- if {} is specified you must also specify {} and vice-versa", ORG1_ID, ORG2_ID);
+ return;
+ }
+ }
if (StringUtils.isNotEmpty( line.getOptionValue( THREADS_ARG_NAME ) )) {
try {
threadCount = Integer.parseInt( line.getOptionValue( THREADS_ARG_NAME ) );
@@ -118,9 +155,23 @@ public class DuplicateOrgRepair extends ToolBase {
}
logger.info( "DuplicateOrgRepair tool starting up... manager: " + manager.getClass().getSimpleName() );
-
- buildOrgMaps();
-
+
+ if ( org1uuid != null && org2uuid != null ) {
+
+ Org org1 = manager.getOrg( org1uuid );
+ Org org2 = manager.getOrg( org2uuid );
+
+ if ( org1.getName().equals( org2.getName() )) {
+ buildOrgMaps( org1, org2 );
+ } else {
+ logger.error("org1 and org2 do not have same duplicate name");
+ return;
+ }
+
+ } else {
+ buildOrgMaps();
+ }
+
augmentUserOrgsMap();
manager.logDuplicates( duplicatesByName );
@@ -137,7 +188,38 @@ public class DuplicateOrgRepair extends ToolBase {
return new RepairManager();
}
+
+ private void buildOrgMaps(Org org1, Org org2) {
+
+ Set<Org> orgs = new HashSet<Org>();
+ orgs.add( org1 );
+ orgs.add( org2 );
+ orgsByName.put( org1.getName(), orgs );
+ duplicatesByName.put( org1.getName(), orgs );
+
+ orgsById.put( org1.getId(), org1 );
+ orgsById.put( org2.getId(), org2 );
+
+ for ( Org org : orgs ) {
+ try {
+ Set<OrgUser> orgUsers = manager.getOrgUsers( org );
+ for (OrgUser user : orgUsers) {
+ Set<Org> usersOrgs = orgsByUser.get( user );
+ if (usersOrgs == null) {
+ usersOrgs = new HashSet<Org>();
+ orgsByUser.put( user, usersOrgs );
+ }
+ usersOrgs.add( org );
+ }
+ } catch (Exception e) {
+ logger.error( "Error getting users for org {}:{}", org.getName(), org.getId() );
+ logger.error( "Stack trace is: ", e );
+ }
+ }
+ }
+
+
/**
* build map of orgs by name, orgs by id, orgs by user and duplicate orgs by name
*/
@@ -528,7 +610,22 @@ public class DuplicateOrgRepair extends ToolBase {
}
}
}
+
+ @Override
+ public Org getOrg(UUID uuid) throws Exception {
+
+ EntityManager em = emf.getEntityManager( CassandraService.MANAGEMENT_APPLICATION_ID );
+ Entity entity = em.get( uuid );
+
+ Org org = new Org(
+ entity.getUuid(),
+ entity.getProperty( "path" )+"",
+ entity.getCreated() );
+ org.sourceValue = entity;
+
+ return org;
+ }
}
http://git-wip-us.apache.org/repos/asf/usergrid/blob/33a74e82/stack/tools/src/test/java/org/apache/usergrid/tools/DuplicateOrgRepairTest.java
----------------------------------------------------------------------
diff --git a/stack/tools/src/test/java/org/apache/usergrid/tools/DuplicateOrgRepairTest.java b/stack/tools/src/test/java/org/apache/usergrid/tools/DuplicateOrgRepairTest.java
index f871e50..daf40d3 100644
--- a/stack/tools/src/test/java/org/apache/usergrid/tools/DuplicateOrgRepairTest.java
+++ b/stack/tools/src/test/java/org/apache/usergrid/tools/DuplicateOrgRepairTest.java
@@ -85,6 +85,46 @@ public class DuplicateOrgRepairTest {
}
}).toBlocking().lastOrDefault( null );
}
+
+
+ @org.junit.Test
+ public void testMockWithOneDup() throws Exception {
+
+ int numOrgs = 1; // create 1 org and a dup
+
+ final DuplicateOrgRepair dor = new DuplicateOrgRepair();
+ dor.testing = true;
+
+ dor.manager = new Manager( numOrgs );
+
+ assertEquals( "must start with dups",
+ 2 * numOrgs, (long)dor.manager.getOrgs().count().toBlocking().single());
+
+ dor.startTool( new String[] {
+ "org1", ((Manager)dor.manager).usersByOrg.keySet().iterator().next().getId()+"",
+ "org2", ((Manager)dor.manager).usersByOrg.keySet().iterator().next().getId()+""
+ }, false ); // false means do not call System.exit()
+
+ assertEquals( "must remove dups",
+ numOrgs, (long)dor.manager.getOrgs().count().toBlocking().single());
+
+ dor.manager.getOrgs().doOnNext( new Action1<Org>() {
+ @Override
+ public void call(Org org) {
+ try {
+ assertEquals("remaining orgs should have right number of users",
+ 3, dor.manager.getOrgUsers(org).size());
+
+ assertEquals("remaining orgs should have right number of apps",
+ 3, dor.manager.getOrgApps(org).size());
+
+ } catch (Exception e) {
+ logger.error("Error counting apps or users: " + e.getMessage(), e);
+ fail("Error counting apps or users");
+ }
+ }
+ }).toBlocking().lastOrDefault( null );
+ }
@org.junit.Test
@@ -262,6 +302,8 @@ public class DuplicateOrgRepairTest {
Map<OrgUser, Set<Org>> orgsByUser = new HashMap<OrgUser, Set<Org>>();
Map<Org, Set<UUID>> appsByOrg = new HashMap<Org, Set<UUID>>();
+
+ Map<UUID, Org> orgsById = new HashMap<UUID, Org>();
/**
@@ -283,6 +325,9 @@ public class DuplicateOrgRepairTest {
}
Org org2 = new Org( UUID.randomUUID(), "org_" + i, System.currentTimeMillis() );
+ orgsById.put( org1.getId(), org1 );
+ orgsById.put( org2.getId(), org2 );
+
OrgUser usera = new OrgUser( UUID.randomUUID(), "user_" + i + "_a" );
OrgUser userb = new OrgUser( UUID.randomUUID(), "user_" + i + "_b" );
OrgUser userc = new OrgUser( UUID.randomUUID(), "user_" + i + "_c" );
@@ -403,5 +448,10 @@ public class DuplicateOrgRepairTest {
}
}
}
+
+ @Override
+ public Org getOrg(UUID uuid) throws Exception {
+ return orgsById.get(uuid);
+ }
}
}