diff --git a/__tests__/integration/core-api/__support__/setup.ts b/__tests__/integration/core-api/__support__/setup.ts index 4ebfcd03f6..07af1e5dbf 100644 --- a/__tests__/integration/core-api/__support__/setup.ts +++ b/__tests__/integration/core-api/__support__/setup.ts @@ -4,6 +4,7 @@ import { Utils } from "@arkecosystem/crypto"; import delay from "delay"; import { defaults } from "../../../../packages/core-api/src/defaults"; import { plugin } from "../../../../packages/core-api/src/plugin"; +import { defaults as defaultsPeer } from "../../../../packages/core-p2p/src/defaults"; import { registerWithContainer, setUpContainer } from "../../../utils/helpers/container"; import { delegates } from "../../../utils/fixtures"; @@ -36,6 +37,8 @@ const setUp = async () => { ], }); + app.register("pkg.p2p.opts", asValue(defaultsPeer)); + const databaseService = app.resolvePlugin("database"); await databaseService.buildWallets(); await databaseService.saveRound(round); diff --git a/__tests__/integration/core-api/handlers/peers.test.ts b/__tests__/integration/core-api/handlers/peers.test.ts index 6528e432aa..482cec2063 100644 --- a/__tests__/integration/core-api/handlers/peers.test.ts +++ b/__tests__/integration/core-api/handlers/peers.test.ts @@ -8,29 +8,37 @@ import { utils } from "../utils"; const peers = [ { ip: "1.0.0.99", - port: 4000, + port: 4002, version: "2.4.0-next.3", + state: { + height: 2, + }, + latency: 2, }, { ip: "1.0.0.98", - port: 4000, + port: 4002, version: "2.4.0-next.1", + state: { + height: 1, + }, + latency: 1, }, ]; beforeAll(async () => { await setUp(); - const peerMocks = peers - .map(mock => { - const peerMock = new Peer(mock.ip); - (peerMock as any).port = mock.port; - peerMock.version = mock.version; - return peerMock; - }) - .reduce((result, mock) => ({ ...result, [mock.ip]: mock }), {}); + const peerMocks = JSON.parse(JSON.stringify(peers)).map(mock => { + const peer = new Peer(mock.ip); + (peer as any).port = mock.port; - for (const peerMock of Object.values(peerMocks)) { + delete mock.port; + + return Object.assign(peer, mock); + }); + + for (const peerMock of peerMocks) { app.resolvePlugin("p2p") .getStorage() .setPeer(peerMock); @@ -65,6 +73,42 @@ describe("API 2.0 - Peers", () => { expect(response.data.data[0].ip).toBe(peers[0].ip); expect(response.data.data[1].ip).toBe(peers[1].ip); }); + + it("should GET all the peers sorted by height,asc", async () => { + const response = await utils.request("GET", "peers", { orderBy: "height:asc" }); + expect(response).toBeSuccessfulResponse(); + expect(response.data.data).toBeArrayOfSize(peers.length); + expect(response.data.data[0]).toBeObject(); + expect(response.data.data[0].ip).toBe(peers[1].ip); + expect(response.data.data[1].ip).toBe(peers[0].ip); + }); + + it("should GET all the peers sorted by height,desc", async () => { + const response = await utils.request("GET", "peers", { orderBy: "height:desc" }); + expect(response).toBeSuccessfulResponse(); + expect(response.data.data).toBeArrayOfSize(peers.length); + expect(response.data.data[0]).toBeObject(); + expect(response.data.data[0].ip).toBe(peers[0].ip); + expect(response.data.data[1].ip).toBe(peers[1].ip); + }); + + it("should GET all the peers sorted by latency,asc", async () => { + const response = await utils.request("GET", "peers", { orderBy: "latency:asc" }); + expect(response).toBeSuccessfulResponse(); + expect(response.data.data).toBeArrayOfSize(peers.length); + expect(response.data.data[0]).toBeObject(); + expect(response.data.data[0].ip).toBe(peers[1].ip); + expect(response.data.data[1].ip).toBe(peers[0].ip); + }); + + it("should GET all the peers sorted by latency,desc", async () => { + const response = await utils.request("GET", "peers", { orderBy: "latency:desc" }); + expect(response).toBeSuccessfulResponse(); + expect(response.data.data).toBeArrayOfSize(peers.length); + expect(response.data.data[0]).toBeObject(); + expect(response.data.data[0].ip).toBe(peers[0].ip); + expect(response.data.data[1].ip).toBe(peers[1].ip); + }); }); describe("GET /peers/:ip", () => { diff --git a/packages/core-api/src/handlers/peers/controller.ts b/packages/core-api/src/handlers/peers/controller.ts index fe8e9a19c0..618b3b367a 100644 --- a/packages/core-api/src/handlers/peers/controller.ts +++ b/packages/core-api/src/handlers/peers/controller.ts @@ -1,4 +1,5 @@ import { P2P } from "@arkecosystem/core-interfaces"; +import { orderBy } from "@arkecosystem/utils"; import Boom from "@hapi/boom"; import Hapi from "@hapi/hapi"; import { get } from "dottie"; @@ -7,12 +8,11 @@ import { Controller } from "../shared/controller"; export class PeersController extends Controller { public async index(request: Hapi.Request, h: Hapi.ResponseToolkit) { - const allPeers: P2P.IPeer[] = this.blockchain.p2p.getStorage().getPeers(); + const allPeers: P2P.IPeer[] = [...this.blockchain.p2p.getStorage().getPeers()]; - let result = allPeers.sort((a, b) => a.latency - b.latency); - result = request.query.version - ? result.filter(peer => peer.version === (request.query as any).version) - : result; + let result = request.query.version + ? allPeers.filter(peer => peer.version === (request.query as any).version) + : allPeers; const count: number = result.length; @@ -28,16 +28,37 @@ export class PeersController extends Controller { offset = 0; } - const orderBy: string = request.query.orderBy as string; - if (orderBy) { - const order = orderBy.split(":"); + const order: string = request.query.orderBy as string; + if (order) { + const orderByMapped = order.split(":").map(p => p.toLowerCase()); - if (order[0] === "version") { - result = - order[1].toUpperCase() === "ASC" - ? result.sort((a, b) => semver.compare(a[order[0]], b[order[0]])) - : result.sort((a, b) => semver.rcompare(a[order[0]], b[order[0]])); + switch (orderByMapped[0]) { + case "version": { + result = + orderByMapped[1] === "asc" + ? result.sort((a, b) => semver.compare(a[orderByMapped[0]], b[orderByMapped[0]])) + : result.sort((a, b) => semver.rcompare(a[orderByMapped[0]], b[orderByMapped[0]])); + break; + } + case "height": { + result = orderBy( + result, + el => el.state[orderByMapped[0]], + orderByMapped[1] === "asc" ? "asc" : "desc", + ); + break; + } + case "latency": { + result = orderBy(result, orderByMapped[0], orderByMapped[1] === "asc" ? "asc" : "desc"); + break; + } + default: { + result = result.sort((a, b) => a.latency - b.latency); + break; + } } + } else { + result = result.sort((a, b) => a.latency - b.latency); } result = result.slice(offset, offset + limit);