package catalogpublication

import (
	"context"
	"database/sql"
	"errors"
	"regexp"
	"testing"

	"github.com/DATA-DOG/go-sqlmock"
	"github.com/pingcap-inc/nexuscrm-controlplane/internal/catalogwriter"
)

func TestWriterGenerationExhaustionMapsToPublicationConflict(t *testing.T) {
	if err := mapWriterError(catalogwriter.ErrLineageExhausted); !errors.Is(
		err, ErrConflict,
	) {
		t.Fatalf("writer generation exhaustion = %v", err)
	}
}

func TestBeginPersistsOneFencedCandidate(t *testing.T) {
	authority, mock, closeDB := mockPublicationAuthority(t)
	defer closeDB()
	request := validBeginRequest()
	candidateDigest, requestDigest, err := validateBeginRequest(request)
	if err != nil {
		t.Fatal(err)
	}

	mock.ExpectBegin()
	mock.ExpectQuery("SELECT OrgId, CommandId, RequestDigest").
		WithArgs(request.Candidate.OrgID, request.CommandID).
		WillReturnError(sql.ErrNoRows)
	expectNoCandidateSourceJournal(mock, request.Candidate.OrgID, request.CommandID)
	mock.ExpectQuery("SELECT OrgId, RuntimeAudience, CatalogRevision, LastSecurityEpoch, ActiveOperationId").
		WithArgs(request.Candidate.OrgID).
		WillReturnError(sql.ErrNoRows)
	mock.ExpectExec("INSERT INTO _System_CatalogOrgState").
		WithArgs(request.Candidate.OrgID, request.RuntimeAudience).
		WillReturnResult(sqlmock.NewResult(0, 1))
	expectNoCandidateSourceJournal(mock, request.Candidate.OrgID, request.CommandID)
	mock.ExpectQuery("SELECT OrgId, ActivePublicationPresent").
		WithArgs(request.Candidate.OrgID).
		WillReturnError(sql.ErrNoRows)
	mock.ExpectExec("INSERT INTO _System_CatalogPublicationActive").
		WithArgs(request.Candidate.OrgID).
		WillReturnResult(sqlmock.NewResult(0, 1))
	expectPublicationInsert(mock, Publication{Digest: candidateDigest, Binding: request.Candidate}).
		WillReturnResult(sqlmock.NewResult(0, 1))
	mock.ExpectExec("INSERT INTO _System_CatalogPublicationCommand").
		WithArgs(request.Candidate.OrgID, request.CommandID, requestDigest, request.RuntimeAudience,
			candidateDigest, false, nil).
		WillReturnResult(sqlmock.NewResult(0, 1))
	mock.ExpectExec("INSERT INTO _System_CatalogPublicationCandidate").
		WithArgs(request.Candidate.OrgID, request.CommandID, candidateDigest).
		WillReturnResult(sqlmock.NewResult(0, 1))
	mock.ExpectExec("UPDATE _System_CatalogOrgState SET ActiveOperationId").
		WithArgs(request.CommandID, "1", request.Candidate.OrgID, "0", "0", "0").
		WillReturnResult(sqlmock.NewResult(0, 1))
	mock.ExpectCommit()

	command, err := authority.Begin(context.Background(), request)
	if err != nil {
		t.Fatal(err)
	}
	if command.CandidatePublicationDigest != candidateDigest || command.RequestDigest != requestDigest || command.State != CommandReserved {
		t.Fatalf("command = %#v", command)
	}
	assertMockExpectations(t, mock)
}

func TestBeginChangedRetryConflictsBeforeInspectingPointer(t *testing.T) {
	authority, mock, closeDB := mockPublicationAuthority(t)
	defer closeDB()
	original := validBeginRequest()
	candidateDigest, requestDigest, err := validateBeginRequest(original)
	if err != nil {
		t.Fatal(err)
	}
	changed := original
	changed.Candidate.CatalogRevision = 2

	mock.ExpectBegin()
	mock.ExpectQuery("SELECT OrgId, CommandId, RequestDigest").
		WithArgs(original.Candidate.OrgID, original.CommandID).
		WillReturnRows(sqlmock.NewRows([]string{
			"OrgId", "CommandId", "RequestDigest", "RuntimeAudience", "CandidatePublicationDigest",
			"ExpectedPriorPresent", "ExpectedPriorDigest", "State",
		}).AddRow(original.Candidate.OrgID, original.CommandID, requestDigest, original.RuntimeAudience,
			candidateDigest, false, nil, string(CommandReserved)))
	expectNoCandidateSourceJournal(mock, original.Candidate.OrgID, original.CommandID)
	mock.ExpectRollback()

	if _, err := authority.Begin(context.Background(), changed); !errors.Is(err, ErrConflict) {
		t.Fatalf("changed retry error = %v", err)
	}
	assertMockExpectations(t, mock)
}

func TestCommitSelectsCandidateAndPersistsAtomicOutcome(t *testing.T) {
	authority, mock, closeDB := mockPublicationAuthority(t)
	defer closeDB()
	request := validBeginRequest()
	candidateDigest, requestDigest, err := validateBeginRequest(request)
	if err != nil {
		t.Fatal(err)
	}
	command := commandFromRequest(request, candidateDigest, requestDigest)
	wantedOutcome := Outcome{
		OrgID:                      request.Candidate.OrgID,
		CommandID:                  request.CommandID,
		CandidatePublicationDigest: candidateDigest,
		Result:                     ResultSelected,
		ObservedPrior:              Reference{},
		ResultingActive:            Reference{Present: true, Digest: candidateDigest},
	}
	wantedOutcome.OutcomeDigest, err = canonicalOutcomeDigest(wantedOutcome)
	if err != nil {
		t.Fatal(err)
	}

	mock.ExpectBegin()
	expectCommandRow(mock, command)
	expectNoCandidateSourceJournal(mock, request.Candidate.OrgID, request.CommandID)
	mock.ExpectQuery("SELECT OrgId, RuntimeAudience, CatalogRevision, LastSecurityEpoch, ActiveOperationId").
		WithArgs(request.Candidate.OrgID).
		WillReturnRows(sqlmock.NewRows([]string{
			"OrgId", "RuntimeAudience", "CatalogRevision", "LastSecurityEpoch",
			"ActiveOperationId", "WriterGeneration",
		}).AddRow(
			request.Candidate.OrgID, request.RuntimeAudience, []byte("0"),
			[]byte("0"), request.CommandID, []byte("1"),
		))
	mock.ExpectQuery("SELECT OrgId, ActivePublicationPresent").
		WithArgs(request.Candidate.OrgID).
		WillReturnRows(sqlmock.NewRows([]string{
			"OrgId", "ActivePublicationPresent", "ActivePublicationDigest", "SelectedByCommandId", "HistorySequence",
		}).AddRow(request.Candidate.OrgID, false, nil, nil, []byte("0")))
	mock.ExpectQuery("SELECT CommandId, CandidatePublicationDigest").
		WithArgs(request.Candidate.OrgID).
		WillReturnRows(sqlmock.NewRows([]string{"CommandId", "CandidatePublicationDigest"}).
			AddRow(request.CommandID, candidateDigest))
	expectPublicationRow(mock, request.Candidate.OrgID, candidateDigest, request)
	mock.ExpectExec(regexp.QuoteMeta(`UPDATE _System_CatalogOrgState
SET CatalogRevision = ?, LastSecurityEpoch = ?, ActiveOperationId = NULL, LastModifiedDate = CURRENT_TIMESTAMP(6)
WHERE OrgId = ? AND ActiveOperationId = ?`)).
		WithArgs("1", "1", request.Candidate.OrgID, request.CommandID).
		WillReturnResult(sqlmock.NewResult(0, 1))
	mock.ExpectExec("UPDATE _System_CatalogPublicationActive").
		WithArgs(candidateDigest, request.CommandID, "1", request.Candidate.OrgID, "0").
		WillReturnResult(sqlmock.NewResult(0, 1))
	mock.ExpectExec("INSERT INTO _System_CatalogPublicationOutcome").
		WithArgs(request.Candidate.OrgID, request.CommandID, candidateDigest, string(ResultSelected),
			false, nil, true, candidateDigest, wantedOutcome.OutcomeDigest).
		WillReturnResult(sqlmock.NewResult(0, 1))
	mock.ExpectExec("INSERT INTO _System_CatalogPublicationHistory").
		WithArgs(request.Candidate.OrgID, "1", request.CommandID, candidateDigest, string(ResultSelected),
			false, nil, true, candidateDigest, wantedOutcome.OutcomeDigest).
		WillReturnResult(sqlmock.NewResult(0, 1))
	mock.ExpectExec("UPDATE _System_CatalogPublicationCommand").
		WithArgs(request.Candidate.OrgID, request.CommandID, candidateDigest).
		WillReturnResult(sqlmock.NewResult(0, 1))
	mock.ExpectExec("DELETE FROM _System_CatalogPublicationCandidate").
		WithArgs(request.Candidate.OrgID, request.CommandID, candidateDigest).
		WillReturnResult(sqlmock.NewResult(0, 1))
	mock.ExpectCommit()

	outcome, err := authority.Commit(context.Background(), request.Candidate.OrgID, request.CommandID)
	if err != nil {
		t.Fatal(err)
	}
	if outcome != wantedOutcome {
		t.Fatalf("outcome = %#v, want %#v", outcome, wantedOutcome)
	}
	assertMockExpectations(t, mock)
}

func TestCompletedCommitRetryReturnsHistoryOutcomeWithoutReadingCurrentPointer(t *testing.T) {
	authority, mock, closeDB := mockPublicationAuthority(t)
	defer closeDB()
	request := validBeginRequest()
	candidateDigest, requestDigest, err := validateBeginRequest(request)
	if err != nil {
		t.Fatal(err)
	}
	command := commandFromRequest(request, candidateDigest, requestDigest)
	command.State = CommandCompleted
	outcome := Outcome{
		OrgID:                      request.Candidate.OrgID,
		CommandID:                  request.CommandID,
		CandidatePublicationDigest: candidateDigest,
		Result:                     ResultSelected,
		ObservedPrior:              Reference{},
		ResultingActive:            Reference{Present: true, Digest: candidateDigest},
	}
	outcome.OutcomeDigest, err = canonicalOutcomeDigest(outcome)
	if err != nil {
		t.Fatal(err)
	}

	mock.ExpectBegin()
	expectCommandRow(mock, command)
	expectNoCandidateSourceJournal(mock, request.Candidate.OrgID, request.CommandID)
	mock.ExpectQuery("SELECT OrgId, CommandId, CandidatePublicationDigest, Result").
		WithArgs(request.Candidate.OrgID, request.CommandID).
		WillReturnRows(sqlmock.NewRows([]string{
			"OrgId", "CommandId", "CandidatePublicationDigest", "Result", "ObservedPriorPresent",
			"ObservedPriorDigest", "ResultingActivePresent", "ResultingActiveDigest", "OutcomeDigest",
		}).AddRow(outcome.OrgID, outcome.CommandID, outcome.CandidatePublicationDigest, string(outcome.Result),
			false, nil, true, candidateDigest, outcome.OutcomeDigest))
	mock.ExpectCommit()

	recovered, err := authority.Commit(context.Background(), request.Candidate.OrgID, request.CommandID)
	if err != nil {
		t.Fatal(err)
	}
	if recovered != outcome {
		t.Fatalf("recovered = %#v, want %#v", recovered, outcome)
	}
	assertMockExpectations(t, mock)
}

func TestCommitRecordsExpectedPriorMismatchAndReleasesFence(t *testing.T) {
	authority, mock, closeDB := mockPublicationAuthority(t)
	defer closeDB()
	request := validBeginRequest()
	request.ExpectedPrior = Reference{Present: true, Digest: testDigest("9")}
	candidateDigest, requestDigest, err := validateBeginRequest(request)
	if err != nil {
		t.Fatal(err)
	}
	command := commandFromRequest(request, candidateDigest, requestDigest)
	wantedOutcome := Outcome{
		OrgID:                      request.Candidate.OrgID,
		CommandID:                  request.CommandID,
		CandidatePublicationDigest: candidateDigest,
		Result:                     ResultExpectedPriorMismatch,
		ObservedPrior:              Reference{},
		ResultingActive:            Reference{},
	}
	wantedOutcome.OutcomeDigest, err = canonicalOutcomeDigest(wantedOutcome)
	if err != nil {
		t.Fatal(err)
	}

	mock.ExpectBegin()
	expectCommandRow(mock, command)
	expectNoCandidateSourceJournal(mock, request.Candidate.OrgID, request.CommandID)
	mock.ExpectQuery("SELECT OrgId, RuntimeAudience, CatalogRevision, LastSecurityEpoch, ActiveOperationId").
		WithArgs(request.Candidate.OrgID).
		WillReturnRows(sqlmock.NewRows([]string{
			"OrgId", "RuntimeAudience", "CatalogRevision", "LastSecurityEpoch",
			"ActiveOperationId", "WriterGeneration",
		}).AddRow(
			request.Candidate.OrgID, request.RuntimeAudience, []byte("0"),
			[]byte("0"), request.CommandID, []byte("1"),
		))
	mock.ExpectQuery("SELECT OrgId, ActivePublicationPresent").
		WithArgs(request.Candidate.OrgID).
		WillReturnRows(sqlmock.NewRows([]string{
			"OrgId", "ActivePublicationPresent", "ActivePublicationDigest", "SelectedByCommandId", "HistorySequence",
		}).AddRow(request.Candidate.OrgID, false, nil, nil, []byte("3")))
	mock.ExpectQuery("SELECT CommandId, CandidatePublicationDigest").
		WithArgs(request.Candidate.OrgID).
		WillReturnRows(sqlmock.NewRows([]string{"CommandId", "CandidatePublicationDigest"}).
			AddRow(request.CommandID, candidateDigest))
	expectPublicationRow(mock, request.Candidate.OrgID, candidateDigest, request)
	mock.ExpectExec(regexp.QuoteMeta(`UPDATE _System_CatalogOrgState
SET ActiveOperationId = NULL, LastModifiedDate = CURRENT_TIMESTAMP(6)
WHERE OrgId = ? AND ActiveOperationId = ?`)).
		WithArgs(request.Candidate.OrgID, request.CommandID).
		WillReturnResult(sqlmock.NewResult(0, 1))
	mock.ExpectExec("UPDATE _System_CatalogPublicationActive").
		WithArgs("4", request.Candidate.OrgID, "3").
		WillReturnResult(sqlmock.NewResult(0, 1))
	mock.ExpectExec("INSERT INTO _System_CatalogPublicationOutcome").
		WithArgs(request.Candidate.OrgID, request.CommandID, candidateDigest, string(ResultExpectedPriorMismatch),
			false, nil, false, nil, wantedOutcome.OutcomeDigest).
		WillReturnResult(sqlmock.NewResult(0, 1))
	mock.ExpectExec("INSERT INTO _System_CatalogPublicationHistory").
		WithArgs(request.Candidate.OrgID, "4", request.CommandID, candidateDigest, string(ResultExpectedPriorMismatch),
			false, nil, false, nil, wantedOutcome.OutcomeDigest).
		WillReturnResult(sqlmock.NewResult(0, 1))
	mock.ExpectExec("UPDATE _System_CatalogPublicationCommand").
		WithArgs(request.Candidate.OrgID, request.CommandID, candidateDigest).
		WillReturnResult(sqlmock.NewResult(0, 1))
	mock.ExpectExec("DELETE FROM _System_CatalogPublicationCandidate").
		WithArgs(request.Candidate.OrgID, request.CommandID, candidateDigest).
		WillReturnResult(sqlmock.NewResult(0, 1))
	mock.ExpectCommit()

	outcome, err := authority.Commit(context.Background(), request.Candidate.OrgID, request.CommandID)
	if err != nil {
		t.Fatal(err)
	}
	if outcome != wantedOutcome {
		t.Fatalf("outcome = %#v, want %#v", outcome, wantedOutcome)
	}
	assertMockExpectations(t, mock)
}

func TestCommitRecordsSelectedNoChangeWithoutAdvancingLineage(t *testing.T) {
	authority, mock, closeDB := mockPublicationAuthority(t)
	defer closeDB()
	request := validBeginRequest()
	candidateDigest, _, err := validateBeginRequest(request)
	if err != nil {
		t.Fatal(err)
	}
	request.ExpectedPrior = Reference{Present: true, Digest: candidateDigest}
	_, requestDigest, err := validateBeginRequest(request)
	if err != nil {
		t.Fatal(err)
	}
	command := commandFromRequest(request, candidateDigest, requestDigest)
	wantedOutcome := Outcome{
		OrgID:                      request.Candidate.OrgID,
		CommandID:                  request.CommandID,
		CandidatePublicationDigest: candidateDigest,
		Result:                     ResultUnchanged,
		ObservedPrior:              request.ExpectedPrior,
		ResultingActive:            request.ExpectedPrior,
	}
	wantedOutcome.OutcomeDigest, err = canonicalOutcomeDigest(wantedOutcome)
	if err != nil {
		t.Fatal(err)
	}

	mock.ExpectBegin()
	expectCommandRow(mock, command)
	expectNoCandidateSourceJournal(mock, request.Candidate.OrgID, request.CommandID)
	mock.ExpectQuery("SELECT OrgId, RuntimeAudience, CatalogRevision, LastSecurityEpoch, ActiveOperationId").
		WithArgs(request.Candidate.OrgID).
		WillReturnRows(sqlmock.NewRows([]string{
			"OrgId", "RuntimeAudience", "CatalogRevision", "LastSecurityEpoch",
			"ActiveOperationId", "WriterGeneration",
		}).AddRow(
			request.Candidate.OrgID, request.RuntimeAudience, []byte("1"),
			[]byte("1"), request.CommandID, []byte("1"),
		))
	mock.ExpectQuery("SELECT OrgId, ActivePublicationPresent").
		WithArgs(request.Candidate.OrgID).
		WillReturnRows(sqlmock.NewRows([]string{
			"OrgId", "ActivePublicationPresent", "ActivePublicationDigest", "SelectedByCommandId", "HistorySequence",
		}).AddRow(request.Candidate.OrgID, true, candidateDigest,
			"018f0000-0000-7000-9000-000000000099", []byte("5")))
	mock.ExpectQuery("SELECT CommandId, CandidatePublicationDigest").
		WithArgs(request.Candidate.OrgID).
		WillReturnRows(sqlmock.NewRows([]string{"CommandId", "CandidatePublicationDigest"}).
			AddRow(request.CommandID, candidateDigest))
	expectPublicationRow(mock, request.Candidate.OrgID, candidateDigest, request)
	expectPublicationRow(mock, request.Candidate.OrgID, candidateDigest, request)
	mock.ExpectExec(regexp.QuoteMeta(`UPDATE _System_CatalogOrgState
SET ActiveOperationId = NULL, LastModifiedDate = CURRENT_TIMESTAMP(6)
WHERE OrgId = ? AND ActiveOperationId = ?`)).
		WithArgs(request.Candidate.OrgID, request.CommandID).
		WillReturnResult(sqlmock.NewResult(0, 1))
	mock.ExpectExec("UPDATE _System_CatalogPublicationActive").
		WithArgs("6", request.Candidate.OrgID, "5").
		WillReturnResult(sqlmock.NewResult(0, 1))
	mock.ExpectExec("INSERT INTO _System_CatalogPublicationOutcome").
		WithArgs(request.Candidate.OrgID, request.CommandID, candidateDigest, string(ResultUnchanged),
			true, candidateDigest, true, candidateDigest, wantedOutcome.OutcomeDigest).
		WillReturnResult(sqlmock.NewResult(0, 1))
	mock.ExpectExec("INSERT INTO _System_CatalogPublicationHistory").
		WithArgs(request.Candidate.OrgID, "6", request.CommandID, candidateDigest, string(ResultUnchanged),
			true, candidateDigest, true, candidateDigest, wantedOutcome.OutcomeDigest).
		WillReturnResult(sqlmock.NewResult(0, 1))
	mock.ExpectExec("UPDATE _System_CatalogPublicationCommand").
		WithArgs(request.Candidate.OrgID, request.CommandID, candidateDigest).
		WillReturnResult(sqlmock.NewResult(0, 1))
	mock.ExpectExec("DELETE FROM _System_CatalogPublicationCandidate").
		WithArgs(request.Candidate.OrgID, request.CommandID, candidateDigest).
		WillReturnResult(sqlmock.NewResult(0, 1))
	mock.ExpectCommit()

	outcome, err := authority.Commit(context.Background(), request.Candidate.OrgID, request.CommandID)
	if err != nil {
		t.Fatal(err)
	}
	if outcome != wantedOutcome {
		t.Fatalf("outcome = %#v, want %#v", outcome, wantedOutcome)
	}
	assertMockExpectations(t, mock)
}

func TestPersistPublicationRecoversExactImmutableDuplicate(t *testing.T) {
	authority, mock, closeDB := mockPublicationAuthority(t)
	defer closeDB()
	request := validBeginRequest()
	digest, _, err := validateBeginRequest(request)
	if err != nil {
		t.Fatal(err)
	}
	publication := Publication{Digest: digest, Binding: request.Candidate}

	mock.ExpectBegin()
	expectPublicationInsert(mock, publication).
		WillReturnError(errors.New("duplicate publication"))
	expectPublicationRow(mock, request.Candidate.OrgID, digest, request)

	tx, err := authority.db.BeginTx(context.Background(), nil)
	if err != nil {
		t.Fatal(err)
	}
	if err := persistPublication(context.Background(), tx, publication); err != nil {
		t.Fatal(err)
	}
	mock.ExpectRollback()
	_ = tx.Rollback()
	assertMockExpectations(t, mock)
}

func mockPublicationAuthority(t *testing.T) (*Authority, sqlmock.Sqlmock, func()) {
	t.Helper()
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatal(err)
	}
	authority, err := New(db)
	if err != nil {
		db.Close()
		t.Fatal(err)
	}
	return authority, mock, func() { _ = db.Close() }
}

func expectCommandRow(mock sqlmock.Sqlmock, command Command) {
	mock.ExpectQuery("SELECT OrgId, CommandId, RequestDigest").
		WithArgs(command.OrgID, command.CommandID).
		WillReturnRows(sqlmock.NewRows([]string{
			"OrgId", "CommandId", "RequestDigest", "RuntimeAudience", "CandidatePublicationDigest",
			"ExpectedPriorPresent", "ExpectedPriorDigest", "State",
		}).AddRow(command.OrgID, command.CommandID, command.RequestDigest, command.RuntimeAudience,
			command.CandidatePublicationDigest, command.ExpectedPrior.Present,
			nullableReference(command.ExpectedPrior), string(command.State)))
}

func expectPublicationRow(mock sqlmock.Sqlmock, orgID, digest string, request BeginRequest) {
	mock.ExpectQuery("SELECT PublicationDigest, BindingVersion, OrgId, CatalogRevision").
		WithArgs(orgID, digest).
		WillReturnRows(sqlmock.NewRows([]string{
			"PublicationDigest", "BindingVersion", "OrgId", "CatalogRevision", "CatalogSnapshotDigest",
			"SchemaGeneration", "EngineGeneration", "LayoutValidationViewDigest",
			"LayoutBundleOwnerVerificationReceiptSetDigest", "LayoutActivationSetDigest",
			"SecurityEpoch", "LayoutRoutingSecurityViewDigest",
		}).AddRow(digest, legacyPublicationBindingVersion, orgID, []byte("1"),
			request.Candidate.CatalogSnapshotDigest, []byte("1"), []byte("1"),
			request.Candidate.LayoutValidationViewDigest, nil, request.Candidate.LayoutActivationSetDigest,
			[]byte("1"), request.Candidate.LayoutRoutingSecurityViewDigest))
}

func expectPublicationInsert(mock sqlmock.Sqlmock, publication Publication) *sqlmock.ExpectedExec {
	return mock.ExpectExec(regexp.QuoteMeta(`INSERT INTO _System_CatalogPublication
(PublicationDigest, BindingVersion, OrgId, CatalogRevision, CatalogSnapshotDigest,
SchemaGeneration, EngineGeneration, LayoutValidationViewDigest,
LayoutBundleOwnerVerificationReceiptSetDigest, LayoutActivationSetDigest,
SecurityEpoch, LayoutRoutingSecurityViewDigest, CreatedDate)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, CURRENT_TIMESTAMP(6))`)).
		WithArgs(
			publication.Digest,
			legacyPublicationBindingVersion,
			publication.Binding.OrgID,
			decimalText(publication.Binding.CatalogRevision),
			publication.Binding.CatalogSnapshotDigest,
			decimalText(publication.Binding.SchemaGeneration),
			decimalText(publication.Binding.EngineGeneration),
			publication.Binding.LayoutValidationViewDigest,
			publication.Binding.LayoutActivationSetDigest,
			decimalText(publication.Binding.SecurityEpoch),
			publication.Binding.LayoutRoutingSecurityViewDigest,
		)
}

func expectNoCandidateSourceJournal(
	mock sqlmock.Sqlmock,
	orgID string,
	commandID string,
) {
	mock.ExpectQuery("SELECT WriterCommandId").
		WithArgs(orgID, commandID).
		WillReturnError(sql.ErrNoRows)
}

func assertMockExpectations(t *testing.T, mock sqlmock.Sqlmock) {
	t.Helper()
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatal(err)
	}
}
