diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..d499b6c --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +Dockerfile +node_modules diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index ffb331d..949f1d4 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -25,57 +25,42 @@ jobs: ref: main - name: Environment run: ls -tlh && env + - name: Start dockerd run: | dockerd -H $DOCKER_HOST --userland-proxy=false & sleep 5 - - name: build containers scripts + + - name: Docker version + run: docker version && docker compose version + + - name: Build laconicd container working-directory: laconicd/tests/sdk_tests run: ./build-laconicd-container.sh - - name: build test-container - run: docker build -t cerc-io/laconic-sdk-tester:local-test -f laconicd/tests/sdk_tests/Dockerfile-sdk . - - name: start containers + - name: Build laconic-sdk container + run: ./scripts/build-sdk-test-container.sh + + - name: Start containers working-directory: laconicd/tests/sdk_tests run: docker compose up -d - - name: run basic tests + - name: Run tests working-directory: laconicd/tests/sdk_tests - run: | - laconicd_key=$( docker compose exec laconicd echo y | docker compose exec laconicd laconicd keys export mykey --unarmored-hex --unsafe ) - cosmos_chain_id=laconic_9000-1 - laconicd_rest_endpoint=http://laconicd:1317 - laconicd_gql_endpoint=http://laconicd:9473/api - sleep 30s - docker compose exec sdk-test-runner sh -c "COSMOS_CHAIN_ID=${cosmos_chain_id} LACONICD_REST_ENDPOINT=${laconicd_rest_endpoint} LACONICD_GQL_ENDPOINT=${laconicd_gql_endpoint} PRIVATE_KEY=${laconicd_key} yarn test" - - name: stop containers + run: ./run-tests.sh + + - name: Start containers (auctions enabled) working-directory: laconicd/tests/sdk_tests - run: docker compose down - - name: start auction containers + env: + TEST_AUCTION_ENABLED: true + run: docker compose up -d + - name: Run auction tests working-directory: laconicd/tests/sdk_tests - run: docker compose -f docker-compose-auctions.yml up -d - - name: run auction tests + run: ./run-tests.sh test:auctions + + - name: Start containers (expiry enabled) working-directory: laconicd/tests/sdk_tests - run: | - laconicd_key=$( docker compose exec laconicd echo y | docker compose exec laconicd laconicd keys export mykey --unarmored-hex --unsafe ) - cosmos_chain_id=laconic_9000-1 - laconicd_rest_endpoint=http://laconicd:1317 - laconicd_gql_endpoint=http://laconicd:9473/api - sleep 30s - docker compose exec sdk-test-runner sh -c "COSMOS_CHAIN_ID=${cosmos_chain_id} LACONICD_REST_ENDPOINT=${laconicd_rest_endpoint} LACONICD_GQL_ENDPOINT=${laconicd_gql_endpoint} PRIVATE_KEY=${laconicd_key} yarn test:auctions" - - name: start containers + env: + TEST_REGISTRY_EXPIRY: true + run: docker compose up -d + - name: Run nameservice expiry tests working-directory: laconicd/tests/sdk_tests - run: docker compose down - - name: start containers - working-directory: laconicd/tests/sdk_tests - run: docker compose -f docker-compose-nameservice.yml up -d - - name: run nameservice expiry tests - working-directory: laconicd/tests/sdk_tests - run: | - laconicd_key=$( docker compose exec laconicd echo y | docker compose exec laconicd laconicd keys export mykey --unarmored-hex --unsafe ) - cosmos_chain_id=laconic_9000-1 - laconicd_rest_endpoint=http://laconicd:1317 - laconicd_gql_endpoint=http://laconicd:9473/api - sleep 30s - docker compose exec sdk-test-runner sh -c "COSMOS_CHAIN_ID=${cosmos_chain_id} LACONICD_REST_ENDPOINT=${laconicd_rest_endpoint} LACONICD_GQL_ENDPOINT=${laconicd_gql_endpoint} PRIVATE_KEY=${laconicd_key} yarn test:nameservice-expiry" - - name: stop nameservice containers - working-directory: laconicd/tests/sdk_tests - run: docker compose down + run: ./run-tests.sh test:nameservice-expiry diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1db9c98..0087247 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -20,53 +20,34 @@ jobs: ref: main - name: Environment run: ls -tlh && env - - name: build containers scripts + + - name: Build laconicd container working-directory: laconicd/tests/sdk_tests run: ./build-laconicd-container.sh - - name: build test-container - run: docker build -t cerc-io/laconic-sdk-tester:local-test -f laconicd/tests/sdk_tests/Dockerfile-sdk . - - name: start containers + - name: Build laconic-sdk container + run: ./scripts/build-sdk-test-container.sh + + - name: Start containers working-directory: laconicd/tests/sdk_tests run: docker compose up -d - - name: run basic tests + - name: Run tests working-directory: laconicd/tests/sdk_tests - run: | - laconicd_key=$( docker compose exec laconicd echo y | docker compose exec laconicd laconicd keys export mykey --unarmored-hex --unsafe ) - cosmos_chain_id=laconic_9000-1 - laconicd_rest_endpoint=http://laconicd:1317 - laconicd_gql_endpoint=http://laconicd:9473/api - sleep 30s - docker compose exec sdk-test-runner sh -c "COSMOS_CHAIN_ID=${cosmos_chain_id} LACONICD_REST_ENDPOINT=${laconicd_rest_endpoint} LACONICD_GQL_ENDPOINT=${laconicd_gql_endpoint} PRIVATE_KEY=${laconicd_key} yarn test" - - name: stop containers + run: ./run-tests.sh + + - name: Start containers (auctions enabled) working-directory: laconicd/tests/sdk_tests - run: docker compose down - - name: start auction containers + env: + TEST_AUCTION_ENABLED: true + run: docker compose up -d + - name: Run auction tests working-directory: laconicd/tests/sdk_tests - run: docker compose -f docker-compose-auctions.yml up -d - - name: run auction tests + run: ./run-tests.sh test:auctions + + - name: Start containers (expiry enabled) working-directory: laconicd/tests/sdk_tests - run: | - laconicd_key=$( docker compose exec laconicd echo y | docker compose exec laconicd laconicd keys export mykey --unarmored-hex --unsafe ) - cosmos_chain_id=laconic_9000-1 - laconicd_rest_endpoint=http://laconicd:1317 - laconicd_gql_endpoint=http://laconicd:9473/api - sleep 30s - docker compose exec sdk-test-runner sh -c "COSMOS_CHAIN_ID=${cosmos_chain_id} LACONICD_REST_ENDPOINT=${laconicd_rest_endpoint} LACONICD_GQL_ENDPOINT=${laconicd_gql_endpoint} PRIVATE_KEY=${laconicd_key} yarn test:auctions" - - name: start containers + env: + TEST_REGISTRY_EXPIRY: true + run: docker compose up -d + - name: Run nameservice expiry tests working-directory: laconicd/tests/sdk_tests - run: docker compose down - - name: start containers - working-directory: laconicd/tests/sdk_tests - run: docker compose -f docker-compose-nameservice.yml up -d - - name: run nameservice expiry tests - working-directory: laconicd/tests/sdk_tests - run: | - laconicd_key=$( docker compose exec laconicd echo y | docker compose exec laconicd laconicd keys export mykey --unarmored-hex --unsafe ) - cosmos_chain_id=laconic_9000-1 - laconicd_rest_endpoint=http://laconicd:1317 - laconicd_gql_endpoint=http://laconicd:9473/api - sleep 30s - docker compose exec sdk-test-runner sh -c "COSMOS_CHAIN_ID=${cosmos_chain_id} LACONICD_REST_ENDPOINT=${laconicd_rest_endpoint} LACONICD_GQL_ENDPOINT=${laconicd_gql_endpoint} PRIVATE_KEY=${laconicd_key} yarn test:nameservice-expiry" - - name: stop nameservice containers - working-directory: laconicd/tests/sdk_tests - run: docker compose down + run: ./run-tests.sh test:nameservice-expiry diff --git a/Dockerfile-sdk b/Dockerfile similarity index 52% rename from Dockerfile-sdk rename to Dockerfile index a959a0c..c542015 100644 --- a/Dockerfile-sdk +++ b/Dockerfile @@ -21,34 +21,18 @@ RUN \ && npm config -g set prefix ${NPM_GLOBAL} \ && su ${USERNAME} -c "npm config -g set prefix ${NPM_GLOBAL}" \ # Install eslint - && su ${USERNAME} -c "umask 0002 && npm install -g eslint lerna jest" \ + && su ${USERNAME} -c "umask 0002 && npm install -g eslint" \ && npm cache clean --force > /dev/null 2>&1 -# [Optional] Uncomment this section to install additional OS packages. -# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ -# && apt-get -y install --no-install-recommends - -# [Optional] Uncomment if you want to install an additional version of node using nvm -# ARG EXTRA_NODE_VERSION=10 -# RUN su node -c "source /usr/local/share/nvm/nvm.sh && nvm install ${EXTRA_NODE_VERSION}" - -# [Optional] Uncomment if you want to install more global node modules -# RUN su node -c "npm install -g " - WORKDIR / -RUN mkdir node_modules && mkdir proto && mkdir scripts && mkdir src -COPY node_modules ./node_modules/ -COPY proto . ./proto/ -COPY scripts ./scripts/ -COPY src ./src/ COPY entrypoint.sh . ENTRYPOINT ["/entrypoint.sh"] -# Placeholder CMD : generally this will be overridden at run time like : -# docker run -it -v /home/builder/cerc/laconic-sdk:/workspace cerc/builder-js sh -c 'cd /workspace && yarn && yarn build' CMD node --version -# Temp hack, clone the laconic-sdk repo here -WORKDIR /app +WORKDIR /app/laconic-sdk + +COPY package*.json . RUN yarn install +COPY . . WORKDIR /app/laconic-sdk diff --git a/scripts/build-sdk-test-container.sh b/scripts/build-sdk-test-container.sh new file mode 100755 index 0000000..14ad3b7 --- /dev/null +++ b/scripts/build-sdk-test-container.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +docker build -t cerc/laconic-sdk-tester:local -f Dockerfile . diff --git a/src/bond.test.ts b/src/bond.test.ts index cfb4e99..5205763 100644 --- a/src/bond.test.ts +++ b/src/bond.test.ts @@ -12,20 +12,10 @@ jest.setTimeout(90 * 1000); const bondTests = () => { let registry: Registry; - let watcher: any; - - let version1: string; - let version2: string; - - let bondId1: string; - let bondId2: string; - - let bondOwner: string; - const publishNewWatcherVersion = async (bondId: string) => { - watcher = await ensureUpdatedConfig(WATCHER_YML_PATH); + let watcher = await ensureUpdatedConfig(WATCHER_YML_PATH); await registry.setRecord({ privateKey, record: watcher.record, bondId }, privateKey, fee); - return watcher.record.version; + return watcher; }; beforeAll(async () => { @@ -33,93 +23,119 @@ const bondTests = () => { }); test('Create bond.', async () => { - bondId1 = await registry.getNextBondId(privateKey); - expect(bondId1).toBeDefined(); + let bondId = await registry.getNextBondId(privateKey); + expect(bondId).toBeDefined(); await registry.createBond({ denom: 'aphoton', amount: '1000000000' }, privateKey, fee); - }) - - test('Get bond by ID.', async () => { - const [bond] = await registry.getBondsByIds([bondId1]); - expect(bond).toBeDefined(); - expect(bond.id).toBe(bondId1); - expect(bond.balance).toHaveLength(1); - expect(bond.balance[0]).toEqual({ type: 'aphoton', quantity: '1000000000' }); - bondOwner = bond.owner; }); - test('Query bonds.', async () => { - const bonds = await registry.queryBonds(); - expect(bonds).toBeDefined(); - const bond = bonds.filter((bond: any) => bond.id === bondId1); - expect(bond).toBeDefined(); - }); + describe('With bond created', () => { + let bond1: any - test('Query bonds by owner.', async () => { - const bonds = await registry.queryBonds({ owner: bondOwner }); - expect(bonds).toBeDefined(); - const bond = bonds.filter((bond: any) => bond.id === bondId1); - expect(bond).toBeDefined(); - }); + beforeAll(async () => { + let bondId1 = await registry.getNextBondId(privateKey); + expect(bondId1).toBeDefined(); + await registry.createBond({ denom: 'aphoton', amount: '1000000000' }, privateKey, fee); - test('Refill bond.', async () => { - await registry.refillBond({ id: bondId1, denom: 'aphoton', amount: '500' }, privateKey, fee); + [bond1] = await registry.getBondsByIds([bondId1]); + expect(bond1).toBeDefined(); + expect(bond1.id).toEqual(bondId1); + }); - const [bond] = await registry.getBondsByIds([bondId1]); - expect(bond).toBeDefined(); - expect(bond.id).toBe(bondId1); - expect(bond.balance).toHaveLength(1); - expect(bond.balance[0]).toEqual({ type: 'aphoton', quantity: '1000000500' }); - }); + test('Get bond by ID.', async () => { + const [bond] = await registry.getBondsByIds([bond1.id]); + expect(bond).toBeDefined(); + expect(bond.id).toBe(bond1.id); + expect(bond.balance).toHaveLength(1); + expect(bond.balance[0]).toEqual({ type: 'aphoton', quantity: '1000000000' }); + }); - test('Withdraw bond.', async () => { - await registry.withdrawBond({ id: bondId1, denom: 'aphoton', amount: '500' }, privateKey, fee); + test('Query bonds.', async () => { + const bonds = await registry.queryBonds(); + expect(bonds).toBeDefined(); + const bond = bonds.filter((bond: any) => bond.id === bond1.id); + expect(bond).toBeDefined(); + }); - const [bond] = await registry.getBondsByIds([bondId1]); - expect(bond).toBeDefined(); - expect(bond.id).toBe(bondId1); - expect(bond.balance).toHaveLength(1); - expect(bond.balance[0]).toEqual({ type: 'aphoton', quantity: '1000000000' }); - }); + test('Query bonds by owner.', async () => { + const bonds = await registry.queryBonds({ owner: bond1.owner }); + expect(bonds).toBeDefined(); + const bond = bonds.filter((bond: any) => bond.id === bond1.id); + expect(bond).toBeDefined(); + }); - test('Cancel bond.', async () => { - await registry.cancelBond({ id: bondId1 }, privateKey, fee); + test('Refill bond.', async () => { + await registry.refillBond({ id: bond1.id, denom: 'aphoton', amount: '500' }, privateKey, fee); + + const [bond] = await registry.getBondsByIds([bond1.id]); + expect(bond).toBeDefined(); + expect(bond.id).toBe(bond1.id); + expect(bond.balance).toHaveLength(1); + expect(bond.balance[0]).toEqual({ type: 'aphoton', quantity: '1000000500' }); + }); + + test('Withdraw bond.', async () => { + await registry.withdrawBond({ id: bond1.id, denom: 'aphoton', amount: '500' }, privateKey, fee); + + const [bond] = await registry.getBondsByIds([bond1.id]); + expect(bond).toBeDefined(); + expect(bond.id).toBe(bond1.id); + expect(bond.balance).toHaveLength(1); + expect(bond.balance[0]).toEqual({ type: 'aphoton', quantity: '1000000000' }); + }); + + test('Cancel bond.', async () => { + await registry.cancelBond({ id: bond1.id }, privateKey, fee); + + const [bond] = await registry.getBondsByIds([bond1.id]); + expect(bond.id).toBe(""); + expect(bond.owner).toBe(""); + expect(bond.balance).toHaveLength(0); + }); - const [bond] = await registry.getBondsByIds([bondId1]); - expect(bond.id).toBe(""); - expect(bond.owner).toBe(""); - expect(bond.balance).toHaveLength(0); }); test('Associate/Dissociate bond.', async () => { + let bondId1: string; + bondId1 = await registry.getNextBondId(privateKey); expect(bondId1).toBeDefined(); await registry.createBond({ denom: 'aphoton', amount: '1000000000' }, privateKey, fee); // Create a new record. - version1 = await publishNewWatcherVersion(bondId1); - let [record1] = await registry.queryRecords({ type: watcher.record.type, version: version1 }, true); + let watcher = await publishNewWatcherVersion(bondId1); + let query = { type: watcher.record.type, url: watcher.record.url, version: watcher.record.version }; + let [record1] = await registry.queryRecords(query, true); expect(record1.bondId).toBe(bondId1); // Dissociate record, query and confirm. await registry.dissociateBond({ recordId: record1.id }, privateKey, fee); - [record1] = await registry.queryRecords({ type: watcher.record.type, version: version1 }, true); + [record1] = await registry.queryRecords(query, true); expect(record1.bondId).toBe(''); // Associate record with bond, query and confirm. await registry.associateBond({ recordId: record1.id, bondId: bondId1 }, privateKey, fee); - [record1] = await registry.queryRecords({ type: watcher.record.type, version: version1 }, true); + [record1] = await registry.queryRecords(query, true); expect(record1.bondId).toBe(bondId1); }); test('Reassociate/Dissociate records.', async () => { + let bondId1: string; + let bondId2: string; + + bondId1 = await registry.getNextBondId(privateKey); + expect(bondId1).toBeDefined(); + await registry.createBond({ denom: 'aphoton', amount: '1000000000' }, privateKey, fee); + // Create a new record version. - version2 = await publishNewWatcherVersion(bondId1); + let watcher = await publishNewWatcherVersion(bondId1); + let queryv1 = { type: watcher.record.type, url: watcher.record.url, version: watcher.record.version }; + let queryv2 = { type: watcher.record.type, url: watcher.record.url, version: watcher.record.version }; // Check version1, version2 as associated with bondId1. let records; - records = await registry.queryRecords({ type: watcher.record.type, version: version1 }, true); + records = await registry.queryRecords(queryv1, true); expect(records[0].bondId).toBe(bondId1); - records = await registry.queryRecords({ type: watcher.record.type, version: version2 }, true); + records = await registry.queryRecords(queryv2, true); expect(records[0].bondId).toBe(bondId1); // Create another bond. @@ -131,16 +147,16 @@ const bondTests = () => { // Reassociate records from bondId1 to bondId2, verify change. await registry.reassociateRecords({ oldBondId: bondId1, newBondId: bondId2 }, privateKey, fee); - records = await registry.queryRecords({ type: watcher.record.type, version: version1 }, true); + records = await registry.queryRecords(queryv1, true); expect(records[0].bondId).toBe(bondId2); - records = await registry.queryRecords({ type: watcher.record.type, version: version2 }, true); + records = await registry.queryRecords(queryv2, true); expect(records[0].bondId).toBe(bondId2); // Dissociate all records from bond, verify change. await registry.dissociateRecords({ bondId: bondId2 }, privateKey, fee); - records = await registry.queryRecords({ type: watcher.record.type, version: version1 }, true); + records = await registry.queryRecords(queryv1, true); expect(records[0].bondId).toBe(''); - records = await registry.queryRecords({ type: watcher.record.type, version: version2 }, true); + records = await registry.queryRecords(queryv2, true); expect(records[0].bondId).toBe(''); }); }; diff --git a/src/index.ts b/src/index.ts index c24adfb..352fa40 100644 --- a/src/index.ts +++ b/src/index.ts @@ -180,9 +180,9 @@ export class Registry { } /** - * Publish record. - * @param transactionPrivateKey - private key in HEX to sign transaction. - */ + * Publish record. + * @param transactionPrivateKey - private key in HEX to sign transaction. + */ async setRecord( params: { privateKey: string, record: any, bondId: string }, transactionPrivateKey: string, diff --git a/src/naming.test.ts b/src/naming.test.ts index 472ff71..2385381 100644 --- a/src/naming.test.ts +++ b/src/naming.test.ts @@ -7,7 +7,7 @@ import { ensureUpdatedConfig, getConfig } from './testing/helper'; const WATCHER_YML_PATH = path.join(__dirname, './testing/data/watcher.yml'); -jest.setTimeout(120 * 1000); +jest.setTimeout(5 * 60 * 1000); const { chainId, restEndpoint, gqlEndpoint, privateKey, fee } = getConfig(); @@ -18,12 +18,6 @@ const namingTests = () => { let watcher: any; let watcherId: string; - let authorityName: string; - let otherAuthorityName: string; - let otherPrivateKey: string; - - let crn: string; - beforeAll(async () => { registry = new Registry(gqlEndpoint, restEndpoint, chainId); @@ -46,221 +40,272 @@ const namingTests = () => { watcherId = result.data.id; }); - test('Reserve authority.', async () => { - authorityName = `laconic-${Date.now()}`; - await registry.reserveAuthority({ name: authorityName }, privateKey, fee); + describe('Authority tests', () => { + test('Reserve authority.', async () => { + const authorityName = `laconic-${Date.now()}`; + + await registry.reserveAuthority({ name: authorityName }, privateKey, fee); + }); + + describe('With authority reserved', () => { + let authorityName: string; + let crn: string; + + beforeAll(async () => { + + authorityName = `laconic-${Date.now()}`; + crn = `crn://${authorityName}/app/test`; + + await registry.reserveAuthority({ name: authorityName }, privateKey, fee); + }) + + test('Lookup authority.', async () => { + const [record] = await registry.lookupAuthorities([authorityName]); + + expect(record).toBeDefined(); + expect(record.ownerAddress).not.toBe(''); + expect(record.ownerPublicKey).not.toBe(''); + expect(Number(record.height)).toBeGreaterThan(0); + }); + + test('Lookup non existing authority', async () => { + const [record] = await registry.lookupAuthorities(['does-not-exist']); + + expect(record.ownerAddress).toBe(''); + expect(record.ownerPublicKey).toBe(''); + expect(Number(record.height)).toBe(0); + }); + + test('Reserve already reserved authority', async () => { + await expect(registry.reserveAuthority({ name: authorityName }, privateKey, fee)). + rejects.toThrow('Name already reserved.'); + }); + + test('Reserve sub-authority.', async () => { + const subAuthority = `echo.${authorityName}`; + await registry.reserveAuthority({ name: subAuthority }, privateKey, fee); + + const [record] = await registry.lookupAuthorities([subAuthority]); + expect(record).toBeDefined(); + expect(record.ownerAddress).not.toBe(''); + expect(record.ownerPublicKey).not.toBe(''); + expect(Number(record.height)).toBeGreaterThan(0); + }); + + test('Reserve sub-authority with different owner.', async () => { + // Create another account, send tx to set public key on the account. + const mnenonic1 = Account.generateMnemonic(); + const otherAccount1 = await Account.generateFromMnemonic(mnenonic1); + await registry.sendCoins({ denom: 'aphoton', amount: '1000000000', destinationAddress: otherAccount1.formattedCosmosAddress }, privateKey, fee); + + const mnenonic2 = Account.generateMnemonic(); + const otherAccount2 = await Account.generateFromMnemonic(mnenonic2); + await registry.sendCoins({ denom: 'aphoton', amount: '10', destinationAddress: otherAccount2.formattedCosmosAddress }, otherAccount1.getPrivateKey(), fee); + + const subAuthority = `halo.${authorityName}`; + await registry.reserveAuthority({ name: subAuthority, owner: otherAccount1.formattedCosmosAddress }, privateKey, fee); + + const [record] = await registry.lookupAuthorities([subAuthority]); + expect(record).toBeDefined(); + expect(record.ownerAddress).toBeDefined(); + expect(record.ownerAddress).toBe(otherAccount1.getCosmosAddress()); + expect(record.ownerPublicKey).toBeDefined(); + expect(Number(record.height)).toBeGreaterThan(0); + }); + + test('Set name for unbonded authority', async () => { + assert(watcherId) + await expect(registry.setName({ crn, cid: watcherId }, privateKey, fee)). + rejects.toThrow('Authority bond not found.'); + }); + + test('Set authority bond', async () => { + await registry.setAuthorityBond({ name: authorityName, bondId }, privateKey, fee); + }); + }); }); - test('Lookup authority.', async () => { - const [record] = await registry.lookupAuthorities([authorityName]); + describe('Naming tests', () => { + let authorityName: string; + let otherAuthorityName: string; + let otherPrivateKey: string; + let otherAccount: Account; - expect(record).toBeDefined(); - expect(record.ownerAddress).not.toBe(''); - expect(record.ownerPublicKey).not.toBe(''); - expect(Number(record.height)).toBeGreaterThan(0); - }); + beforeAll(async () => { + authorityName = `laconic-${Date.now()}`; - test('Lookup non existing authority', async () => { - const [record] = await registry.lookupAuthorities(['does-not-exist']); + await registry.reserveAuthority({ name: authorityName }, privateKey, fee); + await registry.setAuthorityBond({ name: authorityName, bondId }, privateKey, fee); - expect(record.ownerAddress).toBe(''); - expect(record.ownerPublicKey).toBe(''); - expect(Number(record.height)).toBe(0); - }); + // Create another account. + const mnenonic = Account.generateMnemonic(); + otherAccount = await Account.generateFromMnemonic(mnenonic); + await registry.sendCoins({ denom: 'aphoton', amount: '1000000000', destinationAddress: otherAccount.formattedCosmosAddress }, privateKey, fee); - test('Reserve already reserved authority', async () => { - await expect(registry.reserveAuthority({ name: authorityName }, privateKey, fee)).rejects.toThrow('Name already reserved.'); - }); + otherAuthorityName = `other-${Date.now()}`; + otherPrivateKey = otherAccount.privateKey.toString('hex'); + }); - test('Reserve sub-authority.', async () => { - const subAuthority = `echo.${authorityName}`; - await registry.reserveAuthority({ name: subAuthority }, privateKey, fee); + test('Set name', async () => { + const crn = `crn://${authorityName}/app/test1`; - const [record] = await registry.lookupAuthorities([subAuthority]); - expect(record).toBeDefined(); - expect(record.ownerAddress).not.toBe(''); - expect(record.ownerPublicKey).not.toBe(''); - expect(Number(record.height)).toBeGreaterThan(0); - }); + await registry.setName({ crn, cid: watcherId }, privateKey, fee); - test('Reserve sub-authority with different owner.', async () => { - // Create another account, send tx to set public key on the account. - const mnenonic1 = Account.generateMnemonic(); - const otherAccount1 = await Account.generateFromMnemonic(mnenonic1); - await registry.sendCoins({ denom: 'aphoton', amount: '1000000000', destinationAddress: otherAccount1.formattedCosmosAddress }, privateKey, fee); + // Query records should return it (some CRN points to it). + const [record] = await registry.queryRecords({ type: 'WebsiteRegistrationRecord', version: watcher.record.version }); + expect(record).toBeDefined(); + expect(record.names).toHaveLength(1); - const mnenonic2 = Account.generateMnemonic(); - const otherAccount2 = await Account.generateFromMnemonic(mnenonic2); - await registry.sendCoins({ denom: 'aphoton', amount: '10', destinationAddress: otherAccount2.formattedCosmosAddress }, otherAccount1.getPrivateKey(), fee); + await registry.deleteName({ crn }, privateKey, fee); + }); - const subAuthority = `halo.${authorityName}`; - await registry.reserveAuthority({ name: subAuthority, owner: otherAccount1.formattedCosmosAddress }, privateKey, fee); + describe('With name set', () => { + let crn: string; - const [record] = await registry.lookupAuthorities([subAuthority]); - expect(record).toBeDefined(); - expect(record.ownerAddress).toBeDefined(); - expect(record.ownerAddress).toBe(otherAccount1.getCosmosAddress()); - expect(record.ownerPublicKey).toBeDefined(); - expect(Number(record.height)).toBeGreaterThan(0); - }); + beforeAll(async () => { + crn = `crn://${authorityName}/app/test2`; + await registry.setName({ crn, cid: watcherId }, privateKey, fee); + }); - test('Set name for unbonded authority', async () => { - crn = `crn://${authorityName}/app/test`; - assert(watcherId) - await expect(registry.setName({ crn, cid: watcherId }, privateKey, fee)).rejects.toThrow('Authority bond not found.'); - }); + afterAll(async () => { + await registry.deleteName({ crn }, privateKey, fee); + }); - test('Set authority bond', async () => { - await registry.setAuthorityBond({ name: authorityName, bondId }, privateKey, fee); - }); + test('Lookup name', async () => { + const records = await registry.lookupNames([crn]); + expect(records).toBeDefined(); + expect(records).toHaveLength(1); - test('Set name', async () => { - crn = `crn://${authorityName}/app/test`; - await registry.setName({ crn, cid: watcherId }, privateKey, fee); + const [{ latest, history }] = records; + expect(latest).toBeDefined(); + expect(latest.id).toBeDefined(); + expect(latest.id).toBe(watcherId); + expect(latest.height).toBeDefined(); + expect(history).toBeUndefined(); + }); - // Query records should return it (some CRN points to it). - const [record] = await registry.queryRecords({ type: 'WebsiteRegistrationRecord', version: watcher.record.version }); - expect(record).toBeDefined(); - expect(record.names).toHaveLength(1); - }); + test('Resolve name', async () => { + const records = await registry.resolveNames([crn]); + expect(records).toBeDefined(); + expect(records).toHaveLength(1); - test('Lookup name', async () => { - const records = await registry.lookupNames([crn]); - expect(records).toBeDefined(); - expect(records).toHaveLength(1); + const [{ attributes }] = records; + expect(attributes).toEqual(watcher.record); + }); - const [{ latest, history }] = records; - expect(latest).toBeDefined(); - expect(latest.id).toBeDefined(); - expect(latest.id).toBe(watcherId); - expect(latest.height).toBeDefined(); - expect(history).toBeUndefined(); - }); + test('Lookup name with history', async () => { + const updatedWatcher = await ensureUpdatedConfig(WATCHER_YML_PATH); + const result = await registry.setRecord( + { + privateKey, + bondId, + record: updatedWatcher.record + }, + privateKey, + fee + ) - test('Resolve name', async () => { - const records = await registry.resolveNames([crn]); - expect(records).toBeDefined(); - expect(records).toHaveLength(1); + const updatedWatcherId = result.data.id; + await registry.setName({ crn, cid: updatedWatcherId }, privateKey, fee); - const [{ attributes }] = records; - expect(attributes).toEqual(watcher.record); - }); + const records = await registry.lookupNames([crn], true); + expect(records).toHaveLength(1); - test('Lookup name with history', async () => { - const updatedWatcher = await ensureUpdatedConfig(WATCHER_YML_PATH); - const result = await registry.setRecord( - { - privateKey, - bondId, - record: updatedWatcher.record - }, - privateKey, - fee - ) + const [{ latest, history }] = records; + expect(latest).toBeDefined(); + expect(latest.id).toBeDefined(); + expect(latest.id).toBe(updatedWatcherId); + expect(latest.height).toBeDefined(); + expect(history).toBeDefined(); + expect(history).toHaveLength(1); - const updatedWatcherId = result.data.id; - await registry.setName({ crn, cid: updatedWatcherId }, privateKey, fee); + const [oldRecord] = history; + expect(oldRecord).toBeDefined(); + expect(oldRecord.id).toBeDefined(); + expect(oldRecord.id).toBe(watcherId); + expect(oldRecord.height).toBeDefined(); + }); - const records = await registry.lookupNames([crn], true); - expect(records).toHaveLength(1); + test('Delete name', async () => { + await registry.deleteName({ crn }, privateKey, fee); - const [{ latest, history }] = records; - expect(latest).toBeDefined(); - expect(latest.id).toBeDefined(); - expect(latest.id).toBe(updatedWatcherId); - expect(latest.height).toBeDefined(); - expect(history).toBeDefined(); - expect(history).toHaveLength(1); + let records = await registry.lookupNames([crn], true); + expect(records).toBeDefined(); + expect(records).toHaveLength(1); - const [oldRecord] = history; - expect(oldRecord).toBeDefined(); - expect(oldRecord.id).toBeDefined(); - expect(oldRecord.id).toBe(watcherId); - expect(oldRecord.height).toBeDefined(); - }); + const [{ latest }] = records; + expect(latest).toBeDefined(); + expect(latest.id).toBeDefined(); + expect(latest.id).toBe(''); + expect(latest.height).toBeDefined(); - test('Set name without reserving authority', async () => { - await expect(registry.setName({ crn: 'crn://not-reserved/app/test', cid: watcherId }, privateKey, fee)) - .rejects.toThrow('Name authority not found.'); - }); + // Query records should NOT return it (no CRN points to it). + records = await registry.queryRecords({ type: 'WebsiteRegistrationRecord', version: watcher.record.version }); + expect(records).toBeDefined(); + expect(records).toHaveLength(0); - test('Set name for non-owned authority', async () => { - // Create another account. - const mnenonic = Account.generateMnemonic(); - const otherAccount = await Account.generateFromMnemonic(mnenonic); - await registry.sendCoins({ denom: 'aphoton', amount: '1000000000', destinationAddress: otherAccount.formattedCosmosAddress }, privateKey, fee); + // Query all records should return it (all: true). + records = await registry.queryRecords({ type: 'WebsiteRegistrationRecord', version: watcher.record.version }, true); + expect(records).toBeDefined(); + expect(records).toHaveLength(1); + }); - // Other account reserves an authority. - otherAuthorityName = `other-${Date.now()}`; - otherPrivateKey = otherAccount.privateKey.toString('hex'); - await registry.reserveAuthority({ name: otherAuthorityName }, otherPrivateKey, fee); + test('Delete already deleted name', async () => { + await registry.deleteName({ crn }, privateKey, fee); + await registry.deleteName({ crn }, privateKey, fee); - // Try setting name under other authority. - await expect(registry.setName({ crn: `crn://${otherAuthorityName}/app/test`, cid: watcherId }, privateKey, fee)).rejects.toThrow('Access denied.'); - }); + const records = await registry.lookupNames([crn], true); + expect(records).toBeDefined(); + expect(records).toHaveLength(1); - test('Lookup non existing name', async () => { - const records = await registry.lookupNames(['crn://not-reserved/app/test']); - expect(records).toBeDefined(); - expect(records).toHaveLength(1); - const [record] = records; - expect(record).toBeNull(); - }); + const [{ latest }] = records; + expect(latest).toBeDefined(); + expect(latest.id).toBeDefined(); + expect(latest.id).toBe(''); + expect(latest.height).toBeDefined(); + }); + }); - test('Resolve non existing name', async () => { - const records = await registry.resolveNames(['crn://not-reserved/app/test']); - expect(records).toBeDefined(); - expect(records).toHaveLength(1); - const [record] = records; - expect(record).toBeNull(); - }); + test('Set name without reserving authority', async () => { + await expect(registry.setName({ crn: 'crn://not-reserved/app/test', cid: watcherId }, privateKey, fee)) + .rejects.toThrow('Name authority not found.'); + }); - test('Delete name', async () => { - await registry.deleteName({ crn }, privateKey, fee); + test('Set name for non-owned authority', async () => { + await registry.sendCoins({ denom: 'aphoton', amount: '1000000000', destinationAddress: otherAccount.formattedCosmosAddress }, privateKey, fee); - let records = await registry.lookupNames([crn], true); - expect(records).toBeDefined(); - expect(records).toHaveLength(1); + // Other account reserves an authority. + await registry.reserveAuthority({ name: otherAuthorityName }, otherPrivateKey, fee); - const [{ latest }] = records; - expect(latest).toBeDefined(); - expect(latest.id).toBeDefined(); - expect(latest.id).toBe(''); - expect(latest.height).toBeDefined(); + // Try setting name under other authority. + await expect(registry.setName({ crn: `crn://${otherAuthorityName}/app/test`, cid: watcherId }, privateKey, fee)).rejects.toThrow('Access denied.'); + }); - // Query records should NOT return it (no CRN points to it). - records = await registry.queryRecords({ type: 'WebsiteRegistrationRecord', version: watcher.record.version }); - expect(records).toBeDefined(); - expect(records).toHaveLength(0); + test('Delete name for non-owned authority.', async () => { + const otherBondId = await registry.getNextBondId(otherPrivateKey); + await registry.createBond({ denom: 'aphoton', amount: '10000' }, otherPrivateKey, fee); + await registry.setAuthorityBond({ name: otherAuthorityName, bondId: otherBondId }, otherPrivateKey, fee); + await registry.setName({ crn: `crn://${otherAuthorityName}/app/test`, cid: watcherId }, otherPrivateKey, fee); - // Query all records should return it (all: true). - records = await registry.queryRecords({ type: 'WebsiteRegistrationRecord', version: watcher.record.version }, true); - expect(records).toBeDefined(); - expect(records).toHaveLength(1); - }); + // Try deleting name under other authority. + await expect(registry.deleteName({ crn: `crn://${otherAuthorityName}/app/test` }, privateKey, fee)).rejects.toThrow('Access denied.'); + }); - test('Delete already deleted name', async () => { - await registry.deleteName({ crn }, privateKey, fee); + test('Lookup non existing name', async () => { + const records = await registry.lookupNames(['crn://not-reserved/app/test']); + expect(records).toBeDefined(); + expect(records).toHaveLength(1); + const [record] = records; + expect(record).toBeNull(); + }); - const records = await registry.lookupNames([crn], true); - expect(records).toBeDefined(); - expect(records).toHaveLength(1); - - const [{ latest }] = records; - expect(latest).toBeDefined(); - expect(latest.id).toBeDefined(); - expect(latest.id).toBe(''); - expect(latest.height).toBeDefined(); - }); - - test('Delete name for non-owned authority.', async () => { - const otherBondId = await registry.getNextBondId(otherPrivateKey); - await registry.createBond({ denom: 'aphoton', amount: '10000' }, otherPrivateKey, fee); - await registry.setAuthorityBond({ name: otherAuthorityName, bondId: otherBondId }, otherPrivateKey, fee); - await registry.setName({ crn: `crn://${otherAuthorityName}/app/test`, cid: watcherId }, otherPrivateKey, fee); - - // Try deleting name under other authority. - await expect(registry.deleteName({ crn: `crn://${otherAuthorityName}/app/test` }, privateKey, fee)).rejects.toThrow('Access denied.'); + test('Resolve non existing name', async () => { + const records = await registry.resolveNames(['crn://not-reserved/app/test']); + expect(records).toBeDefined(); + expect(records).toHaveLength(1); + const [record] = records; + expect(record).toBeNull(); + }); }); };