refactor(contracts): remove deprecated AIPowerRental contract in favor of bounty system
- 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
This commit is contained in:
415
tests/integration/api_integration.test.js
Normal file
415
tests/integration/api_integration.test.js
Normal file
@@ -0,0 +1,415 @@
|
||||
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();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user