LdapSynchronizer { public SyncResult syncAll() throws LdapException, SyncException { LOG.info("Preparing synchronization environment"); final SyncResult syncResult = new SyncResult(); final Set<String> linkingIds = linker.findIds(); LOG.debug("Using selector {} for synchronization", selector); LOG.info("Starting synchronization of users/profiles"); try (Connection connection = connFactory.getConnection()) { connection.open(); for (LdapEntry entry : selector.select(connection)) { syncResult.fetched++; if (LOG.isDebugEnabled()) { LOG.debug("Synchronizing entry: {}", entry); } syncFetched(entry, linkingIds, syncResult); if (syncResult.fetched % EACH_ENTRIES_COUNT_CHECK_INTERRUPTION == 0) { if (Thread.currentThread().isInterrupted()) { LOG.warn("User/Profile synchronization was interrupted"); LOG.info("Synchronization result: {}", syncResult); return syncResult; } } } } if (removeIfMissing && !linkingIds.isEmpty()) { LOG.info("Removing users missing from ldap storage, users to remove '{}'", linkingIds.size()); for (String linkingId : linkingIds) { try { final User user = linker.findUser(linkingId); userManager.remove(user.getId()); syncResult.removed++; LOG.debug("Removed user '{}'", user.getId()); } catch (NotFoundException | ConflictException | ServerException x) { LOG.info(format("Couldn't remove user '%s' due to occurred error", linkingId), x); syncResult.failed++; } } } LOG.info("Synchronization result: {}", syncResult); return syncResult; } @Inject  LdapSynchronizer(
      ConnectionFactory connFactory,
      LdapEntrySelector selector,
      UserManager userManager,
      ProfileManager profileManager,
      LdapUserIdNormalizer idNormalizer,
      DBInitializer dbInitializer,
      @Named("ldap.sync.period_ms") long syncPeriodMs,
      @Named("ldap.sync.initial_delay_ms") long initDelayMs,
      @Named(USER_ID_ATTRIBUTE_NAME) String userIdAttr,
      @Named(USER_NAME_ATTRIBUTE_NAME) String userNameAttr,
      @Named(USER_EMAIL_ATTRIBUTE_NAME) String userEmailAttr,
      @Named("ldap.sync.profile.attrs") @Nullable Pair<String, String>[] profileAttributes,
      @Named("ldap.sync.update_if_exists") boolean updateIfExists,
      @Named("ldap.sync.remove_if_missing") boolean removeIfMissing,
      DBUserLinker userLinker); void syncAllAsynchronously(); SyncResult syncAll(); @PostConstruct void startScheduler(); @PreDestroy void shutdownScheduler();  }
@Test public void createsAllTheUsersWhenSynchronizedFirstTime() throws Exception { when(entrySelector.select(anyObject())) .thenReturn( asList( createUserEntry("user123"), createUserEntry("user234"), createUserEntry("user345"))); final SyncResult syncResult = synchronizer.syncAll(); assertEquals(syncResult.getProcessed(), 3); assertEquals(syncResult.getCreated(), 3); assertEquals(syncResult.getRemoved(), 0); assertEquals(syncResult.getUpdated(), 0); assertEquals(syncResult.getUpToDate(), 0); assertEquals(syncResult.getRemoved(), 0); assertEquals(syncResult.getSkipped(), 0); assertEquals(syncResult.getFetched(), 3); verify(userManager, times(3)).create(anyObject(), anyBoolean()); verify(profileManager, times(3)).update(anyObject()); }
@Test public void removesThoseUsersWhoAreNotPresentInSelection() throws Exception { final Map<String, LdapEntry> users = new HashMap<>(); users.put("user123", createUserEntry("user123")); users.put("user234", createUserEntry("user234")); when(entrySelector.select(anyObject())).thenReturn(users.values()); existingIds.add("missed-in-selection"); when(userFinder.findUser("missed-in-selection")) .thenReturn(new UserImpl("missed-in-selection", "email", "name")); final SyncResult syncResult = synchronizer.syncAll(); assertEquals(syncResult.getProcessed(), 2); assertEquals(syncResult.getCreated(), 2); assertEquals(syncResult.getRemoved(), 1); assertEquals(syncResult.getUpdated(), 0); assertEquals(syncResult.getUpToDate(), 0); assertEquals(syncResult.getFailed(), 0); assertEquals(syncResult.getSkipped(), 0); assertEquals(syncResult.getFetched(), 2); verify(userManager, times(2)).create(anyObject(), anyBoolean()); verify(profileManager, times(2)).update(anyObject()); verify(userManager).remove("missed-in-selection"); }
@Test public void skipsUsersWhoAreAlreadyPresentInDatabaseAndNotModified() throws Exception { final Map<String, LdapEntry> users = new HashMap<>(); users.put("user123", createUserEntry("user123")); users.put("user234", createUserEntry("user234")); users.put("user345", createUserEntry("user345")); when(entrySelector.select(anyObject())).thenReturn(users.values()); when(profileManager.getById(any())) .thenAnswer( inv -> { final String id = inv.getArguments()[0].toString(); return new ProfileImpl(id, ImmutableMap.of("firstName", "firstName-" + id)); }); final UserMapper mapper = new UserMapper("uid", "cn", "mail"); when(userFinder.findUser(any())) .thenAnswer( inv -> { final String id = inv.getArguments()[0].toString(); return mapper.apply(users.get(id)); }); existingIds.add("user123"); existingIds.add("user345"); final SyncResult syncResult = synchronizer.syncAll(); assertEquals(syncResult.getProcessed(), 3); assertEquals(syncResult.getCreated(), 1); assertEquals(syncResult.getRemoved(), 0); assertEquals(syncResult.getUpToDate(), 2); assertEquals(syncResult.getUpdated(), 0); assertEquals(syncResult.getFailed(), 0); assertEquals(syncResult.getSkipped(), 0); assertEquals(syncResult.getFetched(), 3); verify(userManager).create(anyObject(), anyBoolean()); verify(profileManager).update(anyObject()); verify(userManager, never()).update(anyObject()); }
@Test public void updatesUsersWhoChangedInLdap() throws Exception { final Map<String, LdapEntry> users = new HashMap<>(); users.put("user123", createUserEntry("user123")); users.put("user234", createUserEntry("user234")); when(entrySelector.select(anyObject())).thenReturn(users.values()); when(profileManager.getById(any())) .thenAnswer( inv -> { final String id = inv.getArguments()[0].toString(); return new ProfileImpl(id, ImmutableMap.of("firstName", "new-firstName-" + id)); }); final UserMapper mapper = new UserMapper("uid", "cn", "mail"); when(userFinder.findUser(any())) .thenAnswer( inv -> { final String id = inv.getArguments()[0].toString(); return mapper.apply(users.get(id)); }); existingIds.add("user123"); existingIds.add("user234"); final SyncResult syncResult = synchronizer.syncAll(); assertEquals(syncResult.getProcessed(), 2); assertEquals(syncResult.getCreated(), 0); assertEquals(syncResult.getRemoved(), 0); assertEquals(syncResult.getUpToDate(), 0); assertEquals(syncResult.getUpdated(), 2); assertEquals(syncResult.getFailed(), 0); assertEquals(syncResult.getSkipped(), 0); verify(userManager, never()).update(anyObject()); verify(profileManager, times(2)).update(anyObject()); }
@Test public void skipsUsersIfTheyAlreadyExistAndUpdateIfExistsAttributeIsSetToFalse() throws Exception { synchronizer = new LdapSynchronizer( connFactory, entrySelector, userManager, profileManager, idNormalizer, null, 0, 0, "uid", "cn", "mail", null, false, true, userFinder); when(entrySelector.select(anyObject())) .thenReturn(asList(createUserEntry("user123"), createUserEntry("user234"))); existingIds.add("user123"); existingIds.add("user234"); final SyncResult syncResult = synchronizer.syncAll(); assertEquals(syncResult.getProcessed(), 2); assertEquals(syncResult.getCreated(), 0); assertEquals(syncResult.getUpdated(), 0); assertEquals(syncResult.getUpToDate(), 0); assertEquals(syncResult.getRemoved(), 0); assertEquals(syncResult.getFailed(), 0); assertEquals(syncResult.getSkipped(), 2); }
@Test public void updatesUserIfLinkingAttributeIsDifferentFromId() throws Exception { UserImpl existingUser = new UserImpl("user123", "user123@codenvy.com", "user_123"); DBUserLinker emailFinder = mock(DBUserLinker.class); when(emailFinder.extractId(any(User.class))) .thenAnswer(inv -> ((User) inv.getArguments()[0]).getEmail()); when(emailFinder.findIds()) .thenReturn(new HashSet<>(Collections.singleton(existingUser.getEmail()))); when(emailFinder.findUser(anyString())) .thenAnswer( inv -> { if (!existingUser.getEmail().equals(inv.getArguments()[0])) { throw new NotFoundException("no user " + inv.getArguments()[0]); } return existingUser; }); when(profileManager.getById(existingUser.getId())).thenReturn(mock(ProfileImpl.class)); synchronizer = new LdapSynchronizer( connFactory, entrySelector, userManager, profileManager, idNormalizer, null, 0, 0, "uid", "cn", "mail", null, true, true, emailFinder); ArrayList<LdapEntry> entries = new ArrayList<>(2); entries.add( createUserEntry( "different-id", "different-name", existingUser.getEmail(), "first-name")); entries.add(createUserEntry("new-user")); when(entrySelector.select(anyObject())).thenReturn(entries); final SyncResult syncResult = synchronizer.syncAll(); assertEquals(syncResult.getProcessed(), 2); assertEquals(syncResult.getCreated(), 1); assertEquals(syncResult.getUpdated(), 1); assertEquals(syncResult.getUpToDate(), 0); assertEquals(syncResult.getRemoved(), 0); assertEquals(syncResult.getFailed(), 0); assertEquals(syncResult.getSkipped(), 0); assertEquals(syncResult.getFetched(), 2); ArgumentCaptor<UserImpl> userCaptor = ArgumentCaptor.forClass(UserImpl.class); verify(userManager).update(userCaptor.capture()); UserImpl user = userCaptor.getValue(); assertEquals(user.getId(), existingUser.getId(), "id must be taken from existing user"); assertEquals(user.getName(), "different-name", "name must be updated"); assertEquals(user.getEmail(), existingUser.getEmail(), "linking attribute must be the same"); }