mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Valery Kharseko
17 hours ago a2a74542282fa2eba683661058786625b50c6dc7
opendj-server-legacy/src/test/java/org/opends/server/replication/plugin/ReplayDuringImportTest.java
@@ -831,111 +831,6 @@
  }
  /**
   * A session restart decided while a total update out of this replica is running stops the
   * session that export streams over (issue #1041).
   * <p>
   * What the restart must leave alone is a total update into this replica: the data it is
   * about to replace is read over the session, and the import is the thread the stop waits
   * for. An export is not that: it streams out of a backend nothing is taking away, on a
   * thread of its own, and a session stopped under it is the cut it reports to whoever asked
   * for the total update - the same cut every other stop of the session is. The claim the
   * restart makes for the import is not made here, and the session is stopped as it was
   * before the claim.
   * <p>
   * The export holds the context by standing where it waits for its target to report the
   * start of the total update: the target is a broker of this test, and reports nothing.
   */
  @Test(timeOut = 120_000)
  public void aRestartDecidedWhileAnExportRunsStopsTheSessionItStreamsOver() throws Exception
  {
    final Entry entry = TestCaseUtils.addEntry(
        "dn: cn=renamedSince," + EXAMPLE_DN,
        "objectClass: top",
        "objectClass: person",
        "cn: renamedSince",
        "sn: renamedSince");
    final String entryUUID = getEntryUUID(entry.getName());
    waitUntil(() -> domain.getReplicaInfos().containsKey(EXPORTER_ID),
        "the exporter is not in the replicas of the domain: nothing to export into");
    final AtomicReference<Throwable> exportFailure = new AtomicReference<>();
    final Thread export = new Thread(() -> {
      try
      {
        domain.initializeRemote(EXPORTER_ID, null);
      }
      catch (Throwable t)
      {
        exportFailure.set(t);
      }
    }, "export of " + EXAMPLE_DN);
    // The restart is held after its decision, before the stop: what the case reads is the
    // decision the export was found by, not the session which is down a moment later.
    final CountDownLatch stopHeld = new CountDownLatch(1);
    final CountDownLatch releaseStop = new CountDownLatch(1);
    domain.setServiceStopHook(() -> {
      stopHeld.countDown();
      awaitUninterruptibly(releaseStop);
    });
    final CSN csn = gen.newCSN();
    final AtomicReference<Throwable> replayFailure = new AtomicReference<>();
    final Thread replay = new Thread(() -> {
      try
      {
        replayMsg(new ModifyMsg(csn, DN.valueOf("cn=movedAway," + EXAMPLE_DN),
            generatemods("description", "replayed while the export was running"), entryUUID));
      }
      catch (Throwable t)
      {
        replayFailure.set(t);
      }
    }, "replay of " + csn);
    try
    {
      export.start();
      waitUntil(() -> domain.ieRunning() || exportFailure.get() != null,
          "the export did not claim the import context");
      assertNull(exportFailure.get(),
          "the export failed before it claimed the context: " + exportFailure.get());
      // A change whose entryUUID search never runs spends its attempts in place and asks
      // for the session to be restarted, the way it does in the case above.
      ShortCircuitPlugin.registerShortCircuit(
          OperationType.SEARCH, "PreParse", ResultCode.UNAVAILABLE.intValue());
      try
      {
        replay.start();
        assertTrue(stopHeld.await(30, TimeUnit.SECONDS),
            "the restart left the session to the export: an export is not the owner a total"
                + " update into this replica is");
      }
      finally
      {
        ShortCircuitPlugin.deregisterShortCircuit(OperationType.SEARCH, "PreParse");
      }
      assertTrue(domain.ieRunning(), "the export ended before the restart was decided");
    }
    finally
    {
      releaseStop.countDown();
      domain.setServiceStopHook(null);
    }
    replay.join(60_000);
    assertFalse(replay.isAlive(), "the restart did not end");
    assertNull(replayFailure.get(), "the replay failed: " + replayFailure.get());
    export.join(60_000);
    assertFalse(export.isAlive(), "the export did not end once the session it streams over"
        + " was stopped");
    assertThat(exportFailure.get())
        .as("the export was not told that the session it streams over was cut")
        .isInstanceOf(DirectoryException.class);
    waitUntil(domain::isConnected, "the session was not started back after the restart");
    assertFalse(domain.ieRunning(), "the export which was cut left its context claimed");
  }
  /**
   * Has the exporter start a total update into this replica, and returns once the backend
   * of the domain is deregistered for it: from then on the import is reading the session,
   * and a change replayed here is replayed into no backend.