- Delete AIPowerRental.sol (566 lines) - replaced by AgentBounty.sol - Remove rental agreement system with provider/consumer model - Remove performance metrics and SLA tracking - Remove dispute resolution mechanism - Remove ZK-proof verification for performance - Remove provider/consumer authorization system - Bounty system provides superior developer incentive structure
416 lines
17 KiB
JavaScript
416 lines
17 KiB
JavaScript
const { expect } = require("chai");
|
|
const axios = require("axios");
|
|
const { ethers } = require("hardhat");
|
|
|
|
describe("API Integration Tests", function () {
|
|
let apiBaseUrl, contracts, signers;
|
|
|
|
before(async function () {
|
|
// Setup contracts and API server
|
|
apiBaseUrl = process.env.API_BASE_URL || "http://localhost:3001";
|
|
|
|
// Deploy mock contracts for testing
|
|
const MockERC20 = await ethers.getContractFactory("MockERC20");
|
|
const aitbcToken = await MockERC20.deploy("AITBC Token", "AITBC", ethers.utils.parseEther("1000000"));
|
|
|
|
const MockAgentBounty = await ethers.getContractFactory("MockAgentBounty");
|
|
const agentBounty = await MockAgentBounty.deploy(aitbcToken.address);
|
|
|
|
const MockAgentStaking = await ethers.getContractFactory("MockAgentStaking");
|
|
const agentStaking = await MockAgentStaking.deploy(aitbcToken.address);
|
|
|
|
contracts = { aitbcToken, agentBounty, agentStaking };
|
|
signers = await ethers.getSigners();
|
|
});
|
|
|
|
describe("Bounty API Endpoints", function () {
|
|
it("GET /api/v1/bounties - Should return active bounties", async function () {
|
|
try {
|
|
const response = await axios.get(`${apiBaseUrl}/api/v1/bounties`);
|
|
|
|
expect(response.status).to.equal(200);
|
|
expect(response.data).to.have.property('bounties');
|
|
expect(Array.isArray(response.data.bounties)).to.be.true;
|
|
|
|
// Validate bounty structure
|
|
if (response.data.bounties.length > 0) {
|
|
const bounty = response.data.bounties[0];
|
|
expect(bounty).to.have.property('bounty_id');
|
|
expect(bounty).to.have.property('title');
|
|
expect(bounty).to.have.property('reward_amount');
|
|
expect(bounty).to.have.property('status');
|
|
expect(bounty).to.have.property('deadline');
|
|
}
|
|
} catch (error) {
|
|
// If API server is not running, skip test
|
|
this.skip();
|
|
}
|
|
});
|
|
|
|
it("GET /api/v1/bounties/:id - Should return specific bounty", async function () {
|
|
try {
|
|
const bountyId = 1;
|
|
const response = await axios.get(`${apiBaseUrl}/api/v1/bounties/${bountyId}`);
|
|
|
|
expect(response.status).to.equal(200);
|
|
expect(response.data).to.have.property('bounty_id', bountyId);
|
|
expect(response.data).to.have.property('title');
|
|
expect(response.data).to.have.property('description');
|
|
expect(response.data).to.have.property('reward_amount');
|
|
} catch (error) {
|
|
if (error.response?.status === 404) {
|
|
// Expected if bounty doesn't exist
|
|
expect(error.response.status).to.equal(404);
|
|
} else {
|
|
this.skip();
|
|
}
|
|
}
|
|
});
|
|
|
|
it("POST /api/v1/bounties - Should create new bounty", async function () {
|
|
try {
|
|
const bountyData = {
|
|
title: "Test Bounty",
|
|
description: "A test bounty for API testing",
|
|
reward_amount: "100",
|
|
deadline: new Date(Date.now() + 86400000).toISOString(),
|
|
min_accuracy: 90,
|
|
max_response_time: 3600,
|
|
max_submissions: 10,
|
|
requires_zk_proof: false,
|
|
tags: ["test", "api"],
|
|
tier: "BRONZE",
|
|
difficulty: "easy"
|
|
};
|
|
|
|
const response = await axios.post(`${apiBaseUrl}/api/v1/bounties`, bountyData);
|
|
|
|
expect(response.status).to.equal(201);
|
|
expect(response.data).to.have.property('bounty_id');
|
|
expect(response.data.title).to.equal(bountyData.title);
|
|
} catch (error) {
|
|
if (error.response?.status === 401) {
|
|
// Expected if authentication is required
|
|
expect(error.response.status).to.equal(401);
|
|
} else {
|
|
this.skip();
|
|
}
|
|
}
|
|
});
|
|
|
|
it("GET /api/v1/bounties/categories - Should return bounty categories", async function () {
|
|
try {
|
|
const response = await axios.get(`${apiBaseUrl}/api/v1/bounties/categories`);
|
|
|
|
expect(response.status).to.equal(200);
|
|
expect(response.data).to.have.property('categories');
|
|
expect(Array.isArray(response.data.categories)).to.be.true;
|
|
} catch (error) {
|
|
this.skip();
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("Staking API Endpoints", function () {
|
|
it("GET /api/v1/staking/pools - Should return staking pools", async function () {
|
|
try {
|
|
const response = await axios.get(`${apiBaseUrl}/api/v1/staking/pools`);
|
|
|
|
expect(response.status).to.equal(200);
|
|
expect(response.data).to.have.property('pools');
|
|
expect(Array.isArray(response.data.pools)).to.be.true;
|
|
|
|
if (response.data.pools.length > 0) {
|
|
const pool = response.data.pools[0];
|
|
expect(pool).to.have.property('agent_address');
|
|
expect(pool).to.have.property('total_staked');
|
|
expect(pool).to.have.property('apy');
|
|
expect(pool).to.have.property('staker_count');
|
|
}
|
|
} catch (error) {
|
|
this.skip();
|
|
}
|
|
});
|
|
|
|
it("GET /api/v1/staking/agents - Should return registered agents", async function () {
|
|
try {
|
|
const response = await axios.get(`${apiBaseUrl}/api/v1/staking/agents`);
|
|
|
|
expect(response.status).to.equal(200);
|
|
expect(response.data).to.have.property('agents');
|
|
expect(Array.isArray(response.data.agents)).to.be.true;
|
|
|
|
if (response.data.agents.length > 0) {
|
|
const agent = response.data.agents[0];
|
|
expect(agent).to.have.property('address');
|
|
expect(agent).to.have.property('name');
|
|
expect(agent).to.have.property('total_staked');
|
|
expect(agent).to.have.property('success_rate');
|
|
}
|
|
} catch (error) {
|
|
this.skip();
|
|
}
|
|
});
|
|
|
|
it("POST /api/v1/staking/stake - Should stake tokens", async function () {
|
|
try {
|
|
const stakeData = {
|
|
agent_address: signers[1].address,
|
|
amount: "1000"
|
|
};
|
|
|
|
const response = await axios.post(`${apiBaseUrl}/api/v1/staking/stake`, stakeData);
|
|
|
|
expect(response.status).to.equal(200);
|
|
expect(response.data).to.have.property('transaction_hash');
|
|
expect(response.data).to.have.property('stake_amount');
|
|
} catch (error) {
|
|
if (error.response?.status === 401) {
|
|
expect(error.response.status).to.equal(401);
|
|
} else {
|
|
this.skip();
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("Leaderboard API Endpoints", function () {
|
|
it("GET /api/v1/leaderboard/developers - Should return developer rankings", async function () {
|
|
try {
|
|
const response = await axios.get(`${apiBaseUrl}/api/v1/leaderboard/developers`);
|
|
|
|
expect(response.status).to.equal(200);
|
|
expect(response.data).to.have.property('rankings');
|
|
expect(Array.isArray(response.data.rankings)).to.be.true;
|
|
|
|
if (response.data.rankings.length > 0) {
|
|
const ranking = response.data.rankings[0];
|
|
expect(ranking).to.have.property('rank');
|
|
expect(ranking).to.have.property('address');
|
|
expect(ranking).to.have.property('total_earned');
|
|
expect(ranking).to.have.property('bounties_completed');
|
|
expect(ranking).to.have.property('success_rate');
|
|
}
|
|
} catch (error) {
|
|
this.skip();
|
|
}
|
|
});
|
|
|
|
it("GET /api/v1/leaderboard/top-performers - Should return top performers", async function () {
|
|
try {
|
|
const response = await axios.get(`${apiBaseUrl}/api/v1/leaderboard/top-performers`);
|
|
|
|
expect(response.status).to.equal(200);
|
|
expect(response.data).to.have.property('performers');
|
|
expect(Array.isArray(response.data.performers)).to.be.true;
|
|
|
|
if (response.data.performers.length > 0) {
|
|
const performer = response.data.performers[0];
|
|
expect(performer).to.have.property('address');
|
|
expect(performer).to.have.property('name');
|
|
expect(performer).to.have.property('performance_score');
|
|
expect(performer).to.have.property('category');
|
|
}
|
|
} catch (error) {
|
|
this.skip();
|
|
}
|
|
});
|
|
|
|
it("GET /api/v1/leaderboard/category-stats - Should return category statistics", async function () {
|
|
try {
|
|
const response = await axios.get(`${apiBaseUrl}/api/v1/leaderboard/category-stats`);
|
|
|
|
expect(response.status).to.equal(200);
|
|
expect(response.data).to.have.property('categories');
|
|
expect(Array.isArray(response.data.categories)).to.be.true;
|
|
|
|
if (response.data.categories.length > 0) {
|
|
const category = response.data.categories[0];
|
|
expect(category).to.have.property('category');
|
|
expect(category).to.have.property('total_earnings');
|
|
expect(category).to.have.property('participant_count');
|
|
expect(category).to.have.property('average_performance');
|
|
}
|
|
} catch (error) {
|
|
this.skip();
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("Ecosystem API Endpoints", function () {
|
|
it("GET /api/v1/ecosystem/overview - Should return ecosystem overview", async function () {
|
|
try {
|
|
const response = await axios.get(`${apiBaseUrl}/api/v1/ecosystem/overview`);
|
|
|
|
expect(response.status).to.equal(200);
|
|
expect(response.data).to.have.property('total_developers');
|
|
expect(response.data).to.have.property('total_agents');
|
|
expect(response.data).to.have.property('total_stakers');
|
|
expect(response.data).to.have.property('total_bounties');
|
|
expect(response.data).to.have.property('ecosystem_health_score');
|
|
} catch (error) {
|
|
this.skip();
|
|
}
|
|
});
|
|
|
|
it("GET /api/v1/ecosystem/developer-earnings - Should return developer earnings", async function () {
|
|
try {
|
|
const response = await axios.get(`${apiBaseUrl}/api/v1/ecosystem/developer-earnings?period=weekly&limit=50`);
|
|
|
|
expect(response.status).to.equal(200);
|
|
expect(Array.isArray(response.data)).to.be.true;
|
|
|
|
if (response.data.length > 0) {
|
|
const earnings = response.data[0];
|
|
expect(earnings).to.have.property('address');
|
|
expect(earnings).to.have.property('total_earned');
|
|
expect(earnings).to.have.property('bounties_completed');
|
|
expect(earnings).to.have.property('success_rate');
|
|
}
|
|
} catch (error) {
|
|
this.skip();
|
|
}
|
|
});
|
|
|
|
it("GET /api/v1/ecosystem/treasury-allocation - Should return treasury allocation", async function () {
|
|
try {
|
|
const response = await axios.get(`${apiBaseUrl}/api/v1/ecosystem/treasury-allocation`);
|
|
|
|
expect(response.status).to.equal(200);
|
|
expect(Array.isArray(response.data)).to.be.true;
|
|
|
|
if (response.data.length > 0) {
|
|
const allocation = response.data[0];
|
|
expect(allocation).to.have.property('category');
|
|
expect(allocation).to.have.property('amount');
|
|
expect(allocation).to.have.property('percentage');
|
|
expect(allocation).to.have.property('description');
|
|
}
|
|
} catch (error) {
|
|
this.skip();
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("Error Handling", function () {
|
|
it("Should return 404 for non-existent endpoints", async function () {
|
|
try {
|
|
await axios.get(`${apiBaseUrl}/api/v1/nonexistent`);
|
|
expect.fail("Should have returned 404");
|
|
} catch (error) {
|
|
if (error.response) {
|
|
expect(error.response.status).to.equal(404);
|
|
} else {
|
|
this.skip();
|
|
}
|
|
}
|
|
});
|
|
|
|
it("Should validate request parameters", async function () {
|
|
try {
|
|
const invalidData = {
|
|
title: "", // Invalid empty title
|
|
reward_amount: "-100" // Invalid negative amount
|
|
};
|
|
|
|
await axios.post(`${apiBaseUrl}/api/v1/bounties`, invalidData);
|
|
expect.fail("Should have returned validation error");
|
|
} catch (error) {
|
|
if (error.response) {
|
|
expect(error.response.status).to.be.oneOf([400, 422]);
|
|
} else {
|
|
this.skip();
|
|
}
|
|
}
|
|
});
|
|
|
|
it("Should handle rate limiting", async function () {
|
|
try {
|
|
// Make multiple rapid requests to test rate limiting
|
|
const requests = Array(20).fill().map(() =>
|
|
axios.get(`${apiBaseUrl}/api/v1/bounties`)
|
|
);
|
|
|
|
await Promise.all(requests);
|
|
// If we get here, rate limiting might not be implemented
|
|
console.log("Rate limiting not detected");
|
|
} catch (error) {
|
|
if (error.response?.status === 429) {
|
|
expect(error.response.status).to.equal(429);
|
|
} else {
|
|
this.skip();
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("Authentication & Authorization", function () {
|
|
it("Should require authentication for protected endpoints", async function () {
|
|
try {
|
|
await axios.post(`${apiBaseUrl}/api/v1/bounties`, {
|
|
title: "Test",
|
|
reward_amount: "100"
|
|
});
|
|
expect.fail("Should have required authentication");
|
|
} catch (error) {
|
|
if (error.response) {
|
|
expect(error.response.status).to.equal(401);
|
|
} else {
|
|
this.skip();
|
|
}
|
|
}
|
|
});
|
|
|
|
it("Should validate API tokens", async function () {
|
|
try {
|
|
await axios.get(`${apiBaseUrl}/api/v1/bounties`, {
|
|
headers: {
|
|
'Authorization': 'Bearer invalid-token'
|
|
}
|
|
});
|
|
expect.fail("Should have rejected invalid token");
|
|
} catch (error) {
|
|
if (error.response) {
|
|
expect(error.response.status).to.be.oneOf([401, 403]);
|
|
} else {
|
|
this.skip();
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("Performance Tests", function () {
|
|
it("Should handle concurrent requests", async function () {
|
|
try {
|
|
const startTime = Date.now();
|
|
const requests = Array(10).fill().map(() =>
|
|
axios.get(`${apiBaseUrl}/api/v1/bounties`)
|
|
);
|
|
|
|
await Promise.all(requests);
|
|
const endTime = Date.now();
|
|
const duration = endTime - startTime;
|
|
|
|
// Should complete within reasonable time (5 seconds)
|
|
expect(duration).to.be.lessThan(5000);
|
|
} catch (error) {
|
|
this.skip();
|
|
}
|
|
});
|
|
|
|
it("Should return responses within acceptable time limits", async function () {
|
|
try {
|
|
const startTime = Date.now();
|
|
await axios.get(`${apiBaseUrl}/api/v1/bounties`);
|
|
const endTime = Date.now();
|
|
const responseTime = endTime - startTime;
|
|
|
|
// Should respond within 1 second
|
|
expect(responseTime).to.be.lessThan(1000);
|
|
} catch (error) {
|
|
this.skip();
|
|
}
|
|
});
|
|
});
|
|
});
|