# 감사 실패를 플랫폼 예외로 바꾸는 헬퍼
  MongoAdminGateway.java:120       // The terminal record is written before the failure propagates, and its detail is the
  MongoAdminGateway.java:121       // exception type rather than its message.
  MongoAdminGateway.java:122       audit(MongoAdminAuditRecord.failed(command, failure, clock.instant()));
  MongoAdminGateway.java:123       throw failure;
  MongoAdminGateway.java:124     }
  MongoAdminGateway.java:125   }
  MongoAdminGateway.java:126 
  MongoAdminGateway.java:127   private void audit(MongoAdminAuditRecord record) {
  MongoAdminGateway.java:128     try {
  MongoAdminGateway.java:129       auditSink.accept(record);
  MongoAdminGateway.java:130     } catch (RuntimeException sinkFailed) {
  MongoAdminGateway.java:131       throw MongoOperationRejectedException.of(
  MongoAdminGateway.java:132           "admin.audit",
  MongoAdminGateway.java:133           "the admin audit sink refused the "
  MongoAdminGateway.java:134               + record.phase()
  MongoAdminGateway.java:135               + " record; an administrative operation that cannot be audited does not run");
  MongoAdminGateway.java:136     }
  MongoAdminGateway.java:137   }

# 실행 경로가 그 헬퍼를 쓰는 자리
  MongoAdminGateway.java:83   public <T> T execute(MongoAdminCommand command, MongoAdminApproval approval, Supplier<T> body) {
  MongoAdminGateway.java:84     Objects.requireNonNull(command, "command");
  MongoAdminGateway.java:85     Objects.requireNonNull(body, "body");
  MongoAdminGateway.java:86     Instant now = clock.instant();
  MongoAdminGateway.java:87     authorization.require(command.operation());
  MongoAdminGateway.java:88     if (command.expiredAt(now)) {
  MongoAdminGateway.java:89       throw MongoOperationRejectedException.of(
  MongoAdminGateway.java:90           "admin.command",
  MongoAdminGateway.java:91           "this admin command expired before it ran; a stale command may describe a cluster that no"
  MongoAdminGateway.java:92               + " longer looks like the one it was written for");
  MongoAdminGateway.java:93     }
  MongoAdminGateway.java:94     if (command.operation().highRisk()) {
  MongoAdminGateway.java:95       if (approval == null) {
  MongoAdminGateway.java:96         throw MongoOperationRejectedException.of(
  MongoAdminGateway.java:97             "admin.approval",
  MongoAdminGateway.java:98             "admin operation "
  MongoAdminGateway.java:99                 + command.operation()
  MongoAdminGateway.java:100                 + " destroys data or rewrites a collection; it runs under an approval bound to this"
  MongoAdminGateway.java:101                 + " exact command or not at all");
  MongoAdminGateway.java:102       }
  MongoAdminGateway.java:103       approval.require(command, now);
  MongoAdminGateway.java:104       // Single use. Without this, one approval for one reshard authorizes every later reshard of
  MongoAdminGateway.java:105       // the same shape, including the one nobody discussed.
  MongoAdminGateway.java:106       if (!consumed.add(command.commandDigest())) {
  MongoAdminGateway.java:107         throw MongoOperationRejectedException.of(
  MongoAdminGateway.java:108             "admin.approval",
  MongoAdminGateway.java:109             "this approval has already been used; a second execution needs a second decision");
  MongoAdminGateway.java:110       }
  MongoAdminGateway.java:111     }
  MongoAdminGateway.java:112 
  MongoAdminGateway.java:113     // Fail closed: if the intent cannot be recorded, the command does not run.
  MongoAdminGateway.java:114     audit(MongoAdminAuditRecord.intent(command, now));
  MongoAdminGateway.java:115     try {
  MongoAdminGateway.java:116       T value = body.get();
  MongoAdminGateway.java:117       audit(MongoAdminAuditRecord.succeeded(command, clock.instant()));
  MongoAdminGateway.java:118       return value;
  MongoAdminGateway.java:119     } catch (RuntimeException failure) {
  MongoAdminGateway.java:120       // The terminal record is written before the failure propagates, and its detail is the
  MongoAdminGateway.java:121       // exception type rather than its message.
  MongoAdminGateway.java:122       audit(MongoAdminAuditRecord.failed(command, failure, clock.instant()));
  MongoAdminGateway.java:123       throw failure;
  MongoAdminGateway.java:124     }
  MongoAdminGateway.java:125   }
  MongoAdminGateway.java:126 
  auditSink 를 직접 부르는 줄 : 2 개
  audit 헬퍼를 부르는 줄 : 3 개
  auditSink 라는 이름이 나오는 자리 전부 :
    MongoAdminGateway.java:26  private final Consumer<MongoAdminAuditRecord> auditSink;
    MongoAdminGateway.java:38  Consumer<MongoAdminAuditRecord> auditSink,
    MongoAdminGateway.java:42  this.auditSink = Objects.requireNonNull(auditSink, "auditSink");
    MongoAdminGateway.java:129  auditSink.accept(record);
    MongoAdminGateway.java:147  auditSink.accept(
  audit 헬퍼를 부르는 자리 전부 :
    MongoAdminGateway.java:114  audit(MongoAdminAuditRecord.intent(command, now));
    MongoAdminGateway.java:117  audit(MongoAdminAuditRecord.succeeded(command, clock.instant()));
    MongoAdminGateway.java:122  audit(MongoAdminAuditRecord.failed(command, failure, clock.instant()));

# 드라이런은 헬퍼를 거치지 않는다
  MongoAdminGateway.java:139   /**
  MongoAdminGateway.java:140    * Validates an operation and records the intent without executing it.
  MongoAdminGateway.java:141    *
  MongoAdminGateway.java:142    * <p>The dry run is a prerequisite for every high-risk operation, so it has to be a first-class
  MongoAdminGateway.java:143    * call rather than a flag somebody remembers to pass.
  MongoAdminGateway.java:144    */
  MongoAdminGateway.java:145   public void dryRun(MongoAdminOperation operation, String target, String operator, String reason) {
  MongoAdminGateway.java:146     authorization.require(operation);
  MongoAdminGateway.java:147     auditSink.accept(
  MongoAdminGateway.java:148         MongoAdminAuditRecord.dryRun(operation, target, operator, reason, clock.instant()));
  MongoAdminGateway.java:149   }

# 그 원칙을 고정하는 시험
  MongoAdminAuditStateMachineTest.java:84   @Test
  MongoAdminAuditStateMachineTest.java:85   @DisplayName("an audit sink that fails stops the command from running")
  MongoAdminAuditStateMachineTest.java:86   void anUnauditableCommandDoesNotRun() {
  MongoAdminAuditStateMachineTest.java:87     MongoAdminGateway gateway =
  MongoAdminAuditStateMachineTest.java:88         new MongoAdminGateway(
  MongoAdminAuditStateMachineTest.java:89             new MongoAdminRuntimeGuard(true, "app-credential", "migration-credential"),
  MongoAdminAuditStateMachineTest.java:90             routineAuthorization(),
  MongoAdminAuditStateMachineTest.java:91             record -> {
  MongoAdminAuditStateMachineTest.java:92               throw new IllegalStateException("the audit collection is unreachable");
  MongoAdminAuditStateMachineTest.java:93             },
  MongoAdminAuditStateMachineTest.java:94             FIXED);
  MongoAdminAuditStateMachineTest.java:95     boolean[] ran = {false};
  MongoAdminAuditStateMachineTest.java:96 
  MongoAdminAuditStateMachineTest.java:97     assertThatThrownBy(
  MongoAdminAuditStateMachineTest.java:98             () ->
  MongoAdminAuditStateMachineTest.java:99                 gateway.execute(
  MongoAdminAuditStateMachineTest.java:100                     MongoAdminCommand.routine(
  MongoAdminAuditStateMachineTest.java:101                         MongoAdminOperation.COLL_MOD,
  MongoAdminAuditStateMachineTest.java:102                         "shop.orders",
  MongoAdminAuditStateMachineTest.java:103                         "operator",
  MongoAdminAuditStateMachineTest.java:104                         "widen",
  MongoAdminAuditStateMachineTest.java:105                         NOW.plusSeconds(60)),
  MongoAdminAuditStateMachineTest.java:106                     null,
  MongoAdminAuditStateMachineTest.java:107                     () -> ran[0] = true))
  MongoAdminAuditStateMachineTest.java:108         .isInstanceOf(MongoOperationRejectedException.class)
  MongoAdminAuditStateMachineTest.java:109         .hasMessageContaining("cannot be audited");
  MongoAdminAuditStateMachineTest.java:110     assertThat(ran[0])
  MongoAdminAuditStateMachineTest.java:111         .as("an administrative operation nobody can reconstruct afterwards must not happen")
  MongoAdminAuditStateMachineTest.java:112         .isFalse();
  MongoAdminAuditStateMachineTest.java:113   }
  드라이런의 감사 실패를 보는 시험 줄 : 0 개
  이 게이트웨이의 dryRun 을 부르는 줄 (저장소 전체) : 0 개
  [대조] 같은 게이트웨이의 execute 를 부르는 줄 : 18 개
  그 execute 호출 전부 :
    main · MongoQueryableEncryptionCollectionManager.java:41  adminGateway.execute(
    main · MongoQueryableEncryptionCollectionManager.java:63  adminGateway.execute(
    main · MongoQueryableEncryptionCollectionManager.java:70  adminGateway.execute(MongoAdminOperation.COLL_MOD, collection, operator, reason, apply);
    main · MongoShardingAdminGateway.java:64  adminGateway.execute(MongoAdminOperation.SHARD_COLLECTION, collection, operator, reason, apply);
    main · MongoShardingAdminGateway.java:75  adminGateway.execute(MongoAdminOperation.REFINE_SHARD_KEY, collection, operator, reason, apply);
    main · MongoShardingAdminGateway.java:86  adminGateway.execute(
    main · MongoShardingAdminGateway.java:92  adminGateway.execute(MongoAdminOperation.BALANCER_CONTROL, scope, operator, reason, apply);
    test · MongoAdminAuditStateMachineTest.java:45  gateway.execute(
    test · MongoAdminAuditStateMachineTest.java:65  gateway.execute(
    test · MongoAdminAuditStateMachineTest.java:99  gateway.execute(
    test · MongoAdminAuditStateMachineTest.java:140  assertThatThrownBy(() -> gateway.execute(real, approval, () -> "dropped"))
    test · MongoAdminAuditStateMachineTest.java:155  gateway.execute(
    test · MongoAdminAuditStateMachineTest.java:169  gateway.execute(command, approval, () -> "dropped");
    test · MongoAdminAuditStateMachineTest.java:171  assertThatThrownBy(() -> gateway.execute(command, approval, () -> "dropped"))
    test · MongoAdminAuditStateMachineTest.java:185  gateway.execute(
    test · MongoAdminAuditStateMachineTest.java:198  assertThatThrownBy(() -> gateway.execute(dropOf("shop.orders"), null, () -> "dropped"))
    test · MongoAdminAuditStateMachineTest.java:207  gateway.execute(
    test · MongoAdminRuntimeGuardTest.java:80  gateway.execute(
  [참고] 같은 정규식이 다른 게이트웨이에서 잡는 줄 : 8 개
