Skip to content

Commit

Permalink
Merge pull request #269 from logion-network/feature/fix-guests-support
Browse files Browse the repository at this point in the history
Client fails to connect with guest LLO
  • Loading branch information
gdethier authored Jun 12, 2024
2 parents 24f7249 + 6309d06 commit 16bcba1
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 3 deletions.
2 changes: 1 addition & 1 deletion packages/client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@logion/client",
"version": "0.45.0",
"version": "0.45.1-1",
"description": "logion SDK for client applications",
"main": "dist/index.js",
"packageManager": "yarn@3.2.0",
Expand Down
10 changes: 9 additions & 1 deletion packages/client/src/DirectoryClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,18 @@ export class DirectoryClient {

private getHost(address: string, data: Record<string, PalletLoAuthorityListLegalOfficerData>): PalletLoAuthorityListLegalOfficerData {
const hostOrGuest = data[address];
if(!hostOrGuest) {
throw new Error(`No data for address ${ address }`);
}
if(hostOrGuest.isHost) {
return hostOrGuest;
} else {
return data[hostOrGuest.asGuest.toString()];
const hostAddress = hostOrGuest.asGuest.hostId.toString();
const host = data[hostAddress];
if(!host) {
throw new Error(`No host with address ${ hostAddress }`);
}
return host;
}
}

Expand Down
109 changes: 109 additions & 0 deletions packages/client/test/DirectoryClient.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { LogionNodeApiClass, Region, ValidAccountId } from "@logion/node-api";
import { AxiosInstance, AxiosResponse } from "axios";
import { Mock } from "moq.ts";
import { AccountId32 } from "@polkadot/types/interfaces/types.js";
import type { Bytes } from '@polkadot/types-codec';
import { PalletLoAuthorityListLegalOfficerData, PalletLoAuthorityListHostData, PalletLoAuthorityListGuestData, LogionRuntimeRegion } from "@polkadot/types/lookup";
import { AxiosFactory, DirectoryClient, DirectoryLegalOfficer } from "../src/index.js";
import { EMPTY_POSTAL_ADDRESS, EMPTY_USER_IDENTITY, mockCodecWithToString, mockCodecWithToUtf8, mockOption, mockStorageKey } from "./Utils.js";

describe("DirectoryClient", () => {

it("handles guest LLOs", async () => {
const api = mockApi();
const axiosFactory = mockAxiosFactory();
const client = new DirectoryClient(api, ENDPOINT, axiosFactory);

const legalOfficers = await client.getLegalOfficers();

expect(legalOfficers.length).toBe(2);

expect(legalOfficers[0].node).toBe(BASE_URL);
expect(legalOfficers[0].account).toEqual(ValidAccountId.polkadot(HOST_ADDRESS));
expect(legalOfficers[0].region).toBe(REGION_TYPE);
expect(legalOfficers[0].nodeId).toBe(PEER_ID);

expect(legalOfficers[1].node).toBe(BASE_URL);
expect(legalOfficers[1].account).toEqual(ValidAccountId.polkadot(GUEST_ADDRESS));
expect(legalOfficers[1].region).toBe(REGION_TYPE);
expect(legalOfficers[1].nodeId).toBe(PEER_ID);
});
});

const ENDPOINT = "https://test-directory.logion.network";

function mockApi(): LogionNodeApiClass {
const api = new Mock<LogionNodeApiClass>();
api.setup(instance => instance.polkadot.query.loAuthorityList.legalOfficerSet.entries()).returnsAsync([
[
mockStorageKey([mockCodecWithToString<AccountId32>(HOST_ADDRESS)]),
mockOption<PalletLoAuthorityListLegalOfficerData>(mockHost()),
],
[
mockStorageKey([mockCodecWithToString<AccountId32>(GUEST_ADDRESS)]),
mockOption<PalletLoAuthorityListLegalOfficerData>(mockGuest()),
]
]);
api.setup(instance => instance.adapters.fromLogionRuntimeRegion(REGION)).returns("Europe");
return api.object();
}

const HOST_ADDRESS = "vQvWaxNDdzuX5N3qSvGMtjdHcQdw1TAcPNgx4S1Utd3MTxYeN";
const GUEST_ADDRESS = "vQvZF2YMgKuQhzfF7T3xDjHjuEmcPSUVEoUDPy1mzuSXzFgca";
const REGION_TYPE: Region = "Europe";
const REGION = mockCodecWithToString<LogionRuntimeRegion>(REGION_TYPE);

function mockAxiosFactory(): AxiosFactory {
const axios = mockAxios();
const factory = new Mock<AxiosFactory>();
factory.setup(instance => instance.buildAxiosInstance(ENDPOINT, undefined)).returns(axios);
return factory.object();
}

function mockAxios(): AxiosInstance {
const axios = new Mock<AxiosInstance>();
const response = new Mock<AxiosResponse>();
const legalOfficers: DirectoryLegalOfficer[] = [
{
address: HOST_ADDRESS,
additionalDetails: "",
postalAddress: EMPTY_POSTAL_ADDRESS,
userIdentity: EMPTY_USER_IDENTITY,
},
{
address: GUEST_ADDRESS,
additionalDetails: "",
postalAddress: EMPTY_POSTAL_ADDRESS,
userIdentity: EMPTY_USER_IDENTITY,
},
];
response.setup(instance => instance.data.legalOfficers).returns(legalOfficers);
axios.setup(instance => instance.get("/api/legal-officer")).returnsAsync(response.object());
return axios.object();
}

function mockHost(): PalletLoAuthorityListLegalOfficerData {
const host = new Mock<PalletLoAuthorityListLegalOfficerData>();
host.setup(instance => instance.isHost).returns(true);
const hostData = new Mock<PalletLoAuthorityListHostData>();
hostData.setup(instance => instance.baseUrl)
.returns(mockOption<Bytes>(mockCodecWithToUtf8<Bytes>(BASE_URL)));
hostData.setup(instance => instance.nodeId)
.returns(mockOption<Bytes>(mockCodecWithToString<Bytes>(PEER_ID)));
hostData.setup(instance => instance.region)
.returns(REGION);
host.setup(instance => instance.asHost).returns(hostData.object());
return host.object();
}

const BASE_URL = "https://test-node.logion.network";
const PEER_ID = "12D3KooWJvyP3VJYymTqG7eH4PM5rN4T2agk5cdNCfNymAqwqcvZ";

function mockGuest(): PalletLoAuthorityListLegalOfficerData {
const guest = new Mock<PalletLoAuthorityListLegalOfficerData>();
guest.setup(instance => instance.isHost).returns(false);
const guestData = new Mock<PalletLoAuthorityListGuestData>();
guestData.setup(instance => instance.hostId).returns(mockCodecWithToString(HOST_ADDRESS));
guest.setup(instance => instance.asGuest).returns(guestData.object());
return guest.object();
}
25 changes: 24 additions & 1 deletion packages/client/test/Utils.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { DateTime } from "luxon";
import { ApiPromise } from "@polkadot/api";
import type { StorageKey } from '@polkadot/types';
import { SubmittableExtrinsic } from '@polkadot/api/promise/types';
import { Option, Vec, bool } from "@polkadot/types-codec";
import type { Codec } from '@polkadot/types-codec/types';
import type { Codec, AnyTuple } from '@polkadot/types-codec/types';

import {
AccountTokens,
Expand Down Expand Up @@ -285,3 +286,25 @@ export class MockFile extends File {
}

export const MOCK_FILE = new MockFile();

export function mockStorageKey<T extends AnyTuple = AnyTuple>(args: T): StorageKey<T> {
const key = new Mock<StorageKey<T>>();
key.setup(instance => instance.args).returns(args);
return key.object();
}

export const EMPTY_POSTAL_ADDRESS: LegalOfficerPostalAddress = {
city: "",
company: "",
country: "",
line1: "",
line2: "",
postalCode: "",
};

export const EMPTY_USER_IDENTITY: UserIdentity = {
email: "",
firstName: "",
lastName: "",
phoneNumber: "",
};

0 comments on commit 16bcba1

Please sign in to comment.