// SPDX-License-Identifier: Apache-2.0
import { expect } from 'chai';
import { describe, it } from 'mocha';
import { IntervalLock } from '../../../src/core/lock/interval-lock.js';
import { LockHolder } from '../../../src/core/lock/lock-holder.js';
import { NamespaceName } from '../../../src/types/namespace/namespace-name.js';
import { LockAcquisitionError } from '../../../src/core/lock/lock-acquisition-error.js';
import { StatusCodes } from 'http-status-codes';
import { Duration } from '../../../src/core/time/duration.js';
describe('IntervalLock', () => {
    it('should ignore a renew conflict when latest lease is still held by the same lock holder', async () => {
        const namespace = NamespaceName.of('lock-conflict-test');
        const lockHolder = LockHolder.of('lock-user');
        const leaseName = 'lock-conflict-test';
        let readCallCounter = 0;
        let renewCallCounter = 0;
        let scheduleCallCounter = 0;
        const initialLease = createLease(namespace, leaseName, lockHolder.toJson(), '1');
        const latestLease = createLease(namespace, leaseName, lockHolder.toJson(), '2');
        const renewalService = {
            isScheduled: async () => false,
            schedule: async () => {
                scheduleCallCounter++;
                return 99;
            },
            cancel: async () => true,
            cancelAll: async () => new Map(),
            calculateRenewalDelay: () => Duration.ofSeconds(1),
        };
        const leases = {
            create: async () => {
                throw new Error('not used');
            },
            delete: async () => {
                throw new Error('not used');
            },
            read: async () => {
                readCallCounter++;
                return readCallCounter === 1 ? initialLease : latestLease;
            },
            renew: async () => {
                renewCallCounter++;
                throw createConflictError();
            },
            transfer: async () => {
                throw new Error('not used');
            },
        };
        const namespaces = {
            create: async () => true,
            delete: async () => true,
            list: async () => [],
            has: async () => true,
        };
        const k8 = {
            namespaces: () => namespaces,
            leases: () => leases,
        };
        const k8Factory = {
            getK8: () => k8,
            default: () => k8,
        };
        const lock = new IntervalLock(k8Factory, renewalService, lockHolder, namespace, leaseName, 20);
        await lock.renew();
        expect(readCallCounter).to.equal(2);
        expect(renewCallCounter).to.equal(1);
        expect(scheduleCallCounter).to.equal(1);
    });
    it('should fail renew when conflict resolution reads a lease owned by another holder', async () => {
        const namespace = NamespaceName.of('lock-conflict-fail-test');
        const lockHolder = LockHolder.of('lock-user');
        const otherLockHolder = LockHolder.of('other-user');
        const leaseName = 'lock-conflict-fail-test';
        let readCallCounter = 0;
        const initialLease = createLease(namespace, leaseName, lockHolder.toJson(), '1');
        const conflictingLease = createLease(namespace, leaseName, otherLockHolder.toJson(), '2');
        const renewalService = {
            isScheduled: async () => false,
            schedule: async () => 99,
            cancel: async () => true,
            cancelAll: async () => new Map(),
            calculateRenewalDelay: () => Duration.ofSeconds(1),
        };
        const leases = {
            create: async () => {
                throw new Error('not used');
            },
            delete: async () => {
                throw new Error('not used');
            },
            read: async () => {
                readCallCounter++;
                return readCallCounter === 1 ? initialLease : conflictingLease;
            },
            renew: async () => {
                throw createConflictError();
            },
            transfer: async () => {
                throw new Error('not used');
            },
        };
        const namespaces = {
            create: async () => true,
            delete: async () => true,
            list: async () => [],
            has: async () => true,
        };
        const k8 = {
            namespaces: () => namespaces,
            leases: () => leases,
        };
        const k8Factory = {
            getK8: () => k8,
            default: () => k8,
        };
        const lock = new IntervalLock(k8Factory, renewalService, lockHolder, namespace, leaseName, 20);
        await expect(lock.renew()).to.be.rejectedWith(LockAcquisitionError);
    });
});
function createLease(namespace, leaseName, holderIdentity, resourceVersion) {
    return {
        namespace,
        leaseName,
        holderIdentity,
        durationSeconds: 20,
        acquireTime: new Date(),
        renewTime: new Date(),
        resourceVersion,
    };
}
function createConflictError() {
    const error = new Error('Conflict while replacing lease');
    error.meta = { statusCode: StatusCodes.CONFLICT };
    return error;
}
//# sourceMappingURL=interval-lock.test.js.map