Skip to content

No test for a ModifyDN conflict solved while server-error-result-code is one of the conflict codes #910

Description

@vharseko

ds-cfg-server-error-result-code is configurable and is not validated as a result code, so it can be set to a code conflict resolution owns. #892 (issue #889) made the replay handle that, and one half of it has no test.

The rule

opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/LDAPReplicationDomain.java

private static final Set<ResultCode> CONFLICT_RESULT_CODES = ...   // :407
    ResultCode.NO_SUCH_OBJECT, ResultCode.ENTRY_ALREADY_EXISTS,
    ResultCode.NOT_ALLOWED_ON_RDN, ResultCode.NOT_ALLOWED_ON_NONLEAF,
    // solveNamingConflict(ModifyDNOperation) solves these two as well
    ResultCode.UNWILLING_TO_PERFORM, ResultCode.OBJECTCLASS_VIOLATION);

A change which fails with the configured code is left to solveNamingConflict() when that code is one of these - conflict resolution is the only thing which can solve them - and is treated as a failure of the server only once conflict resolution reports it could not (isConfiguredServerErrorResultCode(), :2795).

What is covered and what is not

  • Covered: UpdateOperationTest.changeConflictResolutionCanNotSolveOnTheServerErrorCodeIsRetried sets the code to 53 (UNWILLING_TO_PERFORM) and asserts that a Delete which keeps failing with it is retried and applied rather than recorded as replayed.
  • Not covered: that a naming conflict which solveNamingConflict(ModifyDNOperation) does solve is still solved with that setting in place. UNWILLING_TO_PERFORM and OBJECTCLASS_VIOLATION were added to the set for the ModifyDN overload specifically, and nothing exercises that combination - the test above would pass with those two entries removed, because the code then routes through isServerFailure() and is retried anyway.

What is needed

A test which, with ds-cfg-server-error-result-code set to 53 (and a second run at 65), replays a ModifyDN whose conflict solveNamingConflict(ModifyDNOperation) resolves through those result codes, and asserts the entry ends up where conflict resolution puts it - not retried as a server failure and not skipped. NamingConflictTest / UpdateOperationTest.namingConflicts are the closest existing scenarios to build it from.

Low severity: it guards a non-default configuration. It is listed here so the gap is recorded rather than rediscovered.

Activity

  1. vharseko commented on Sep 7, 2026

    @vharseko
    MemberAuthor

    The 53 half is written; the 65 half can not be written the way this issue asked for, and the reason is worth recording here.

    UNWILLING_TO_PERFORM (53) - covered

    NamingConflictTest.modifyDnConflictIsSolvedWhileTheServerErrorCodeIsOneOfTheConflictCodes replays a ModifyDNMsg whose newSuperior is - on this replica - a subordinate of the entry being moved, which is what LocalBackendModifyDNOperation reports as UNWILLING_TO_PERFORM (:249, ERR_MODDN_NEW_SUPERIOR_IN_SUBTREE), with ds-cfg-server-error-result-code set to 53. That is a stale-DN conflict of the kind the message's entryUUIDs exist for - the new parent was renamed here - and it is what makes the test watch the guard: the stale DN stays a subordinate of the entry for as long as the message carries it, so no later attempt of the same message applies any better than the first, and the entry only moves once solveNamingConflict(ModifyDNOperation) has rewritten the message with the DNs those entryUUIDs resolve to here.

    Checked against the mutation this issue names - ResultCode.UNWILLING_TO_PERFORM removed from CONFLICT_RESULT_CODES:

    Tests run: 7, Failures: 1
    NamingConflictTest.modifyDnConflictIsSolvedWhileTheServerErrorCodeIsOneOfTheConflictCodes:182
      the naming conflict was not solved: no entry at cn=modDnOnConflictingServerErrorCode,ou=newParent,o=test
      expected [true] but found [false]
    

    The other six tests of the class stay green under that mutation, and so does UpdateOperationTest.changeConflictResolutionCanNotSolveOnTheServerErrorCodeIsRetried (run under it: 1/1) - which is exactly what this issue said about the existing coverage.

    NamingConflictTest rather than UpdateOperationTest because its replayMsg() runs domain.replay() on the test thread, so the scenario is a couple of seconds and has no session or timer in it. setServerErrorResultCode() moved from UpdateOperationTest to ReplicationTestCase so both halves use one helper.

    OBJECTCLASS_VIOLATION (65) - the second run has nothing to fail on

    65 is not reachable for a replayed ModifyDN through the server's own paths: both schema checks in LocalBackendModifyDNOperation are skipped for synchronization operations (:677 is guarded by !isSynchronizationOperation(), and :423 calls applyPreOpModifications(mods, 0, false)), the pre-operation plugins are skipped for them as well (:399), and no backend reports 65 on a rename. The entry in CONFLICT_RESULT_CODES is defensive, so a test for it has to inject the result code.

    A plain ShortCircuitPlugin registration will not do that: it is keyed by operation type and section only, so it fails attempts blind to whether conflict resolution rewrote the message. Once its budget is spent the operation runs for real and applies - which means a test built that way passes with OBJECTCLASS_VIOLATION removed from the set, i.e. it would not be watching anything. What it needs is a short circuit which fails only while the operation still carries the stale DN - a DN predicate on ShortCircuitPlugin, or a test plugin of its own, which is the same tool #909 needs for parking a replay thread.

    Leaving this open for that half.

  2. added a commit that references this issue on Sep 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    replicationtestsTest suites: fixing, enabling, un-disabling

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions