FrozenNodeLogger implements Closeable { public final void lookupById(@NotNull Tree tree) { if (!feature.isEnabled()) { return; } PropertyState primaryType = tree.getProperty(JCR_PRIMARYTYPE); if (primaryType != null && !primaryType.isArray() && primaryType.getValue(Type.STRING).equals(NT_FROZENNODE)) { long now = clock.getTime(); synchronized (FrozenNodeLogger.class) { if (now >= NO_MESSAGE_UNTIL) { NO_MESSAGE_UNTIL = now + LOG_INTERVAL; logFrozenNode(tree); } } } } FrozenNodeLogger(@NotNull Clock clock,
                            @NotNull Whiteboard whiteboard); final void lookupById(@NotNull Tree tree); @Override void close();  }
@Test public void emptyNode() { assertMessages(() -> { logger.lookupById(emptyTree); return 0; }); }
@Test public void folderNode() { assertMessages(() -> { logger.lookupById(folderTree); return 0; }); }
@Test public void frozenNode() { assertMessages(() -> { logger.lookupById(frozenNodeTree); return 1; }); }
@Test public void atMostOncePerSecond() throws Exception { assertMessages(() -> { logger.lookupById(frozenNodeTree); return 1; }); assertMessages(() -> { logger.lookupById(frozenNodeTree); return 0; }); clock.waitUntil(clock.getTime() + 1000); assertMessages(() -> { logger.lookupById(frozenNodeTree); return 1; }); }