more test coverage
Gitea Actions Demo / Explore-Gitea-Actions (push) Failing after 28s Details

This commit is contained in:
Ladd Hoffman 2024-03-11 15:39:25 -05:00
parent ff25ff3382
commit bb9355db15
2 changed files with 178 additions and 68 deletions

View File

@ -84,7 +84,7 @@ contract Work1 is IAcceptAvailability {
}
/// Select a worker randomly from among the available workers, weighted by amount staked
function randomWeightedSelection() internal view returns (uint) {
function randomWeightedSelection() internal view returns (uint stakeIndex) {
uint totalStakes;
for (uint i = 0; i < stakeCount; i++) {
if (stakes[i].assigned) continue;
@ -98,9 +98,11 @@ contract Work1 is IAcceptAvailability {
if (stakes[i].assigned) continue;
if (block.timestamp > stakes[i].endTime) continue;
acc += stakes[i].amount;
if (acc > select) return i;
if (acc > select) {
stakeIndex = i;
break;
}
}
revert("Failed to assign worker"); // Should never get here
}
/// Assign a random available worker
@ -124,9 +126,15 @@ contract Work1 is IAcceptAvailability {
/// Accept work evidence from worker
function submitWorkEvidence(uint requestIndex) external {
WorkRequest storage request = requests[requestIndex];
require(request.status == WorkStatus.Requested);
require(
request.status == WorkStatus.Requested,
"Status must be Requested"
);
AvailabilityStake storage stake = stakes[request.stakeIndex];
require(stake.worker == msg.sender);
require(
stake.worker == msg.sender,
"Worker can only submit evidence for work they are assigned"
);
request.status = WorkStatus.EvidenceSubmitted;
emit WorkEvidenceSubmitted(requestIndex);
}
@ -134,7 +142,10 @@ contract Work1 is IAcceptAvailability {
/// Accept work approval/disapproval from customer
function submitWorkApproval(uint requestIndex, bool approval) external {
WorkRequest storage request = requests[requestIndex];
require(request.status == WorkStatus.EvidenceSubmitted);
require(
request.status == WorkStatus.EvidenceSubmitted,
"Status must be EvidenceSubmitted"
);
AvailabilityStake storage stake = stakes[request.stakeIndex];
request.status = WorkStatus.ApprovalSubmitted;
request.approval = approval;

View File

@ -9,7 +9,6 @@ const { ethers } = require('hardhat');
describe('Work1', () => {
const WORK1_PRICE = 100;
const STAKE_DURATION = 60;
const STAKE_AMOUNT = 50;
async function deploy() {
// Contracts are deployed using the first signer/account by default
const [account1, account2] = await ethers.getSigners();
@ -37,73 +36,173 @@ describe('Work1', () => {
expect(await work1.stakeCount()).to.equal(0);
});
it('Should be able to receive availability stake', async () => {
const { dao, work1, account1 } = await loadFixture(deploy);
await dao.stakeAvailability(work1.target, STAKE_AMOUNT, STAKE_DURATION);
expect(await dao.balanceOf(account1)).to.equal(STAKE_AMOUNT);
expect(await dao.balanceOf(work1.target)).to.equal(STAKE_AMOUNT);
expect(await work1.stakeCount()).to.equal(1);
const stake = await work1.stakes(0);
expect(stake.worker).to.equal(account1);
expect(stake.amount).to.equal(STAKE_AMOUNT);
expect(stake.endTime).to.equal(await time.latest() + STAKE_DURATION);
describe('Stake availability', () => {
let dao;
let work1;
let account1;
let account2;
beforeEach(async () => {
const setup = await loadFixture(deploy);
dao = setup.dao;
work1 = setup.work1;
account1 = setup.account1;
account2 = setup.account2;
await dao.stakeAvailability(work1.target, 50, STAKE_DURATION);
});
it('Should be able to stake availability', async () => {
expect(await dao.balanceOf(account1)).to.equal(50);
expect(await dao.balanceOf(work1.target)).to.equal(50);
expect(await work1.stakeCount()).to.equal(1);
const stake = await work1.stakes(0);
expect(stake.worker).to.equal(account1);
expect(stake.amount).to.equal(50);
expect(stake.endTime).to.equal(await time.latest() + STAKE_DURATION);
});
it('should be able to reclaim staked availability after duration elapses', async () => {
expect(await dao.balanceOf(account1)).to.equal(50);
time.increase(STAKE_DURATION + 1);
await work1.reclaimAvailability(0);
expect(await dao.balanceOf(account1)).to.equal(100);
});
it('should not be able to reclaim staked availability before duration elapses', async () => {
await expect(work1.reclaimAvailability(0)).to.be.revertedWith('Stake duration has not yet elapsed');
});
it('should not be able to reclaim availability staked by another account', async () => {
time.increase(STAKE_DURATION + 1);
await expect(work1.connect(account2).reclaimAvailability(0)).to.be.revertedWith('Worker can only reclaim their own availability stake');
});
it('should be able to extend the duration of an availability stake before it expires', async () => {
await time.increase(STAKE_DURATION / 2);
await work1.extendAvailability(0, STAKE_DURATION);
});
it('should be able to extend the duration of an availability stake after it expires', async () => {
await time.increase(STAKE_DURATION * 2);
await work1.extendAvailability(0, STAKE_DURATION);
});
it('should not be able to extend the duration of another worker\'s availability stake', async () => {
await time.increase(STAKE_DURATION * 2);
await expect(work1.connect(account2).extendAvailability(0, STAKE_DURATION)).to.be.revertedWith('Worker can only extend their own availability stake');
});
});
it('should be able to request work and assign to a worker', async () => {
const {
dao, work1, account1, account2,
} = await loadFixture(deploy);
await dao.stakeAvailability(work1.target, STAKE_AMOUNT, STAKE_DURATION, { from: account1 });
const requestWork = () => work1.connect(account2).requestWork({ value: WORK1_PRICE });
await expect(requestWork()).to.emit(work1, 'WorkAssigned').withArgs(account1, 0);
expect(await work1.requestCount()).to.equal(1);
const request = await work1.requests(0);
expect(request.customer).to.equal(account2);
describe('Request and assign work', () => {
it('should be able to request work and assign to a worker', async () => {
const {
dao, work1, account1, account2,
} = await loadFixture(deploy);
await dao.stakeAvailability(work1.target, 50, STAKE_DURATION, { from: account1 });
const requestWork = () => work1.connect(account2).requestWork({ value: WORK1_PRICE });
await expect(requestWork()).to.emit(work1, 'WorkAssigned').withArgs(account1, 0);
expect(await work1.requestCount()).to.equal(1);
const request = await work1.requests(0);
expect(request.customer).to.equal(account2);
});
it('should not be able to request work if there are no availability stakes', async () => {
const {
work1, account2,
} = await loadFixture(deploy);
const requestWork = () => work1.connect(account2).requestWork({ value: WORK1_PRICE });
await expect(requestWork()).to.be.revertedWith('No available worker stakes');
});
it('should not assign work to an expired availability stake', async () => {
const {
dao, work1, account1, account2,
} = await loadFixture(deploy);
await dao.stakeAvailability(work1.target, 50, STAKE_DURATION, { from: account1 });
const requestWork = () => work1.connect(account2).requestWork({ value: WORK1_PRICE });
await time.increase(61);
await expect(requestWork()).to.be.revertedWith('No available worker stakes');
});
it('should not assign work to the same availability stake twice', async () => {
const {
dao, work1, account1, account2,
} = await loadFixture(deploy);
await dao.stakeAvailability(work1.target, 50, STAKE_DURATION, { from: account1 });
const requestWork = () => work1.connect(account2).requestWork({ value: WORK1_PRICE });
await expect(requestWork()).to.emit(work1, 'WorkAssigned').withArgs(account1, 0);
await expect(requestWork()).to.be.revertedWith('No available worker stakes');
});
});
it('should not be able to request work if there are no availability stakes', async () => {
const {
work1, account2,
} = await loadFixture(deploy);
const requestWork = () => work1.connect(account2).requestWork({ value: WORK1_PRICE });
await expect(requestWork()).to.be.revertedWith('No available worker stakes');
});
describe('Work evidence and approval/disapproval', () => {
it('should be able to submit work evidence', async () => {
const {
dao, work1, account1, account2,
} = await loadFixture(deploy);
await dao.stakeAvailability(work1.target, 50, STAKE_DURATION, { from: account1 });
await work1.connect(account2).requestWork({ value: WORK1_PRICE });
await expect(work1.submitWorkEvidence(0)).to.emit(work1, 'WorkEvidenceSubmitted').withArgs(0);
});
it('should not assign work to an expired availability stake', async () => {
const {
dao, work1, account1, account2,
} = await loadFixture(deploy);
await dao.stakeAvailability(work1.target, STAKE_AMOUNT, STAKE_DURATION, { from: account1 });
const requestWork = () => work1.connect(account2).requestWork({ value: WORK1_PRICE });
await time.increase(61);
await expect(requestWork()).to.be.revertedWith('No available worker stakes');
});
it('should not assign work to the same availability stake twice', async () => {
const {
dao, work1, account1, account2,
} = await loadFixture(deploy);
await dao.stakeAvailability(work1.target, STAKE_AMOUNT, STAKE_DURATION, { from: account1 });
const requestWork = () => work1.connect(account2).requestWork({ value: WORK1_PRICE });
await expect(requestWork()).to.emit(work1, 'WorkAssigned').withArgs(account1, 0);
await expect(requestWork()).to.be.revertedWith('No available worker stakes');
});
it('should not be able to submit work evidence twice', async () => {
const {
dao, work1, account1, account2,
} = await loadFixture(deploy);
await dao.stakeAvailability(work1.target, 50, STAKE_DURATION, { from: account1 });
await work1.connect(account2).requestWork({ value: WORK1_PRICE });
await expect(work1.submitWorkEvidence(0)).to.emit(work1, 'WorkEvidenceSubmitted').withArgs(0);
await expect(work1.submitWorkEvidence(0)).to.be.revertedWith('Status must be Requested');
});
it('should be able to submit work evidence', async () => {
const {
dao, work1, account1, account2,
} = await loadFixture(deploy);
await dao.stakeAvailability(work1.target, STAKE_AMOUNT, STAKE_DURATION, { from: account1 });
await work1.connect(account2).requestWork({ value: WORK1_PRICE });
await expect(work1.submitWorkEvidence(0)).to.emit(work1, 'WorkEvidenceSubmitted').withArgs(0);
});
it('should not be able to submit work evidence for a different worker', async () => {
const {
dao, work1, account1, account2,
} = await loadFixture(deploy);
await dao.stakeAvailability(work1.target, 50, STAKE_DURATION, { from: account1 });
await work1.connect(account2).requestWork({ value: WORK1_PRICE });
await expect(work1.connect(account2).submitWorkEvidence(0)).to.be.revertedWith('Worker can only submit evidence for work they are assigned');
});
it('should be able to submit work approval', async () => {
const {
dao, work1, account1, account2,
} = await loadFixture(deploy);
await dao.stakeAvailability(work1.target, STAKE_AMOUNT, STAKE_DURATION, { from: account1 });
await work1.connect(account2).requestWork({ value: WORK1_PRICE });
await work1.submitWorkEvidence(0);
await expect(work1.submitWorkApproval(0, true)).to.emit(dao, 'ValidationPoolInitiated').withArgs(1);
it('should be able to submit work approval', async () => {
const {
dao, work1, account1, account2,
} = await loadFixture(deploy);
await dao.stakeAvailability(work1.target, 50, STAKE_DURATION, { from: account1 });
await work1.connect(account2).requestWork({ value: WORK1_PRICE });
await work1.submitWorkEvidence(0);
await expect(work1.submitWorkApproval(0, true)).to.emit(dao, 'ValidationPoolInitiated').withArgs(1);
});
it('should not be able to submit work approval/disapproval twice', async () => {
const {
dao, work1, account1, account2,
} = await loadFixture(deploy);
await dao.stakeAvailability(work1.target, 50, STAKE_DURATION, { from: account1 });
await work1.connect(account2).requestWork({ value: WORK1_PRICE });
await work1.submitWorkEvidence(0);
await expect(work1.submitWorkApproval(0, true)).to.emit(dao, 'ValidationPoolInitiated').withArgs(1);
await expect(work1.submitWorkApproval(0, true)).to.be.revertedWith('Status must be EvidenceSubmitted');
});
it('should not be able to submit work evidence after work approval', async () => {
const {
dao, work1, account1, account2,
} = await loadFixture(deploy);
await dao.stakeAvailability(work1.target, 50, STAKE_DURATION, { from: account1 });
await work1.connect(account2).requestWork({ value: WORK1_PRICE });
await work1.submitWorkEvidence(0);
await expect(work1.submitWorkApproval(0, true)).to.emit(dao, 'ValidationPoolInitiated').withArgs(1);
await expect(work1.submitWorkEvidence(0)).to.be.revertedWith('Status must be Requested');
});
it('should not be able to submit work approval/disapproval before work evidence', async () => {
const {
dao, work1, account1, account2,
} = await loadFixture(deploy);
await dao.stakeAvailability(work1.target, 50, STAKE_DURATION, { from: account1 });
await work1.connect(account2).requestWork({ value: WORK1_PRICE });
await expect(work1.submitWorkApproval(0, true)).to.be.revertedWith('Status must be EvidenceSubmitted');
});
});
});