Skip to content
This repository was archived by the owner on Mar 11, 2025. It is now read-only.

Commit 59ad74c

Browse files
name-service-js: add tests (#4013)
1 parent d0bd334 commit 59ad74c

File tree

6 files changed

+1598
-560
lines changed

6 files changed

+1598
-560
lines changed

.github/workflows/pull-request-name-service.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,18 @@ jobs:
5757
- name: Build and test
5858
run: ./ci/cargo-test-sbf.sh name-service
5959

60+
- name: Upload programs
61+
uses: actions/upload-artifact@v2
62+
with:
63+
name: name-service-programs
64+
path: "target/deploy/*.so"
65+
if-no-files-found: error
66+
6067
js-test:
6168
runs-on: ubuntu-latest
6269
env:
6370
NODE_VERSION: 14.x
71+
needs: cargo-test-sbf
6472
steps:
6573
- uses: actions/checkout@v2
6674
- name: Use Node.js ${{ env.NODE_VERSION }}
@@ -73,4 +81,9 @@ jobs:
7381
key: node-${{ hashFiles('name-service/js/yarn.lock') }}
7482
restore-keys: |
7583
node-
84+
- name: Download programs
85+
uses: actions/download-artifact@v2
86+
with:
87+
name: name-service-programs
88+
path: target/deploy
7689
- run: ./ci/js-test-name-service.sh

ci/js-test-name-service.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ cd name-service/js
1010
yarn install --pure-lockfile
1111
yarn lint
1212
yarn build
13+
yarn test

name-service/js/package.json

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,26 +23,36 @@
2323
"prepublish": "tsc",
2424
"lint": "yarn pretty && eslint --max-warnings 0 'src/*.ts'",
2525
"lint:fix": "yarn pretty:fix && eslint 'src/*.ts' --fix",
26-
"pretty": "prettier --check 'src/*.ts'",
27-
"pretty:fix": "prettier --write 'src/*.ts'",
28-
"doc": "yarn typedoc src/index.ts"
26+
"pretty": "prettier --check '{src/*.ts,test/*/*.ts}'",
27+
"pretty:fix": "prettier --write '{src/*.ts,test/*/*.ts}'",
28+
"doc": "yarn typedoc src/index.ts",
29+
"test": "yarn test:unit && yarn test:e2e",
30+
"test:unit": "mocha test/unit",
31+
"test:e2e": "start-server-and-test 'solana-test-validator --bpf-program namesLPneVptA9Z5rqUDD9tMTWEJwofgaYwp8cawRkX ../../target/deploy/spl_name_service.so --reset --quiet' http://localhost:8899/health 'mocha test/e2e'"
2932
},
3033
"prettier": {
3134
"singleQuote": true
3235
},
3336
"devDependencies": {
3437
"@tsconfig/recommended": "^1.0.1",
38+
"@types/chai": "^4.3.4",
39+
"@types/chai-as-promised": "^7.1.5",
40+
"@types/mocha": "^10.0.1",
3541
"@types/node": "^14.14.20",
3642
"@typescript-eslint/eslint-plugin": "^4.0.1",
3743
"@typescript-eslint/parser": "^4.0.1",
3844
"babel-eslint": "^10.1.0",
45+
"chai": "^4.3.7",
46+
"chai-as-promised": "^7.1.1",
3947
"eslint": "^7.8.0",
4048
"eslint-config-prettier": "^6.11.0",
4149
"eslint-plugin-eslint-comments": "^3.2.0",
4250
"eslint-plugin-functional": "^3.0.2",
4351
"eslint-plugin-import": "^2.22.0",
52+
"mocha": "^10.2.0",
4453
"prettier": "^2.2.1",
45-
"ts-node": "^9.1.1",
54+
"start-server-and-test": "^1.15.3",
55+
"ts-node": "^10.9.1",
4656
"typedoc": "^0.22.11",
4757
"typescript": "^4.1.3"
4858
},
@@ -51,5 +61,12 @@
5161
"@solana/web3.js": "^1.11.0",
5262
"bn.js": "^5.1.3",
5363
"borsh": "^0.4.0"
64+
},
65+
"mocha": {
66+
"require": [
67+
"ts-node/register"
68+
],
69+
"recursive": true,
70+
"extension": "ts"
5471
}
5572
}
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
import {
2+
Connection,
3+
Keypair,
4+
LAMPORTS_PER_SOL,
5+
PublicKey,
6+
sendAndConfirmTransaction,
7+
Transaction,
8+
} from '@solana/web3.js';
9+
import chai, { expect } from 'chai';
10+
import chaiAsPromised from 'chai-as-promised';
11+
12+
import {
13+
createNameRegistry,
14+
deleteNameRegistry,
15+
getHashedName,
16+
getNameAccountKey,
17+
NameRegistryState,
18+
reallocNameAccount,
19+
transferNameOwnership,
20+
updateNameRegistryData,
21+
} from '../../src';
22+
23+
chai.use(chaiAsPromised);
24+
const url = 'http://localhost:8899';
25+
26+
describe('Name Service Program', async () => {
27+
const connection = new Connection(url, 'confirmed');
28+
const payer = Keypair.generate();
29+
const owner = Keypair.generate();
30+
const space = 20;
31+
let nameKey: PublicKey;
32+
let name: string;
33+
before(async () => {
34+
const airdropSignature = await connection.requestAirdrop(
35+
payer.publicKey,
36+
LAMPORTS_PER_SOL
37+
);
38+
await connection.confirmTransaction({
39+
signature: airdropSignature,
40+
...(await connection.getLatestBlockhash()),
41+
});
42+
});
43+
44+
beforeEach(async () => {
45+
name = Math.random().toString() + '.sol';
46+
nameKey = await getNameKey(name);
47+
const lamports = await connection.getMinimumBalanceForRentExemption(
48+
space + NameRegistryState.HEADER_LEN
49+
);
50+
const inst = await createNameRegistry(
51+
connection,
52+
name,
53+
space,
54+
payer.publicKey,
55+
owner.publicKey,
56+
lamports
57+
);
58+
const tx = new Transaction().add(inst);
59+
await sendAndConfirmTransaction(connection, tx, [payer]);
60+
});
61+
62+
it('Create Name Registery', async () => {
63+
const nameAccount = await NameRegistryState.retrieve(connection, nameKey);
64+
nameAccount.owner.equals(owner.publicKey);
65+
expect(nameAccount.data?.length).to.eql(space);
66+
});
67+
it('Update Name Registery', async () => {
68+
const data = Buffer.from('@Dudl');
69+
const inst = await updateNameRegistryData(connection, name, 0, data);
70+
const tx = new Transaction().add(inst);
71+
await sendAndConfirmTransaction(connection, tx, [payer, owner]);
72+
const nameAccount = await NameRegistryState.retrieve(connection, nameKey);
73+
nameAccount.data?.equals(data);
74+
});
75+
it('Transfer Name Ownership', async () => {
76+
const newOwner = Keypair.generate();
77+
const inst = await transferNameOwnership(
78+
connection,
79+
name,
80+
newOwner.publicKey
81+
);
82+
const tx = new Transaction().add(inst);
83+
await sendAndConfirmTransaction(connection, tx, [payer, owner]);
84+
const nameAccount = await NameRegistryState.retrieve(connection, nameKey);
85+
nameAccount.owner.equals(newOwner.publicKey);
86+
});
87+
it('Realloc Name Account to bigger space', async () => {
88+
const inst = await reallocNameAccount(
89+
connection,
90+
name,
91+
space + 10,
92+
payer.publicKey
93+
);
94+
const tx = new Transaction().add(inst);
95+
await sendAndConfirmTransaction(connection, tx, [payer, owner]);
96+
const nameAccount = await NameRegistryState.retrieve(connection, nameKey);
97+
expect(nameAccount.data?.length).to.eql(space + 10);
98+
});
99+
it('Realloc Name Account to smaller space', async () => {
100+
const inst = await reallocNameAccount(
101+
connection,
102+
name,
103+
space - 10,
104+
payer.publicKey
105+
);
106+
const tx = new Transaction().add(inst);
107+
await sendAndConfirmTransaction(connection, tx, [payer, owner]);
108+
const nameAccount = await NameRegistryState.retrieve(connection, nameKey);
109+
expect(nameAccount.data?.length).to.eql(space - 10);
110+
});
111+
it('Delete Name Registry', async () => {
112+
const inst = await deleteNameRegistry(connection, name, payer.publicKey);
113+
const tx = new Transaction().add(inst);
114+
await sendAndConfirmTransaction(connection, tx, [payer, owner]);
115+
const nameAccount = await connection.getAccountInfo(nameKey);
116+
expect(nameAccount).to.be.null;
117+
});
118+
});
119+
120+
const getNameKey = async (
121+
name: string,
122+
nameClass?: PublicKey,
123+
parentName?: PublicKey
124+
) => {
125+
const hashedName = await getHashedName(name);
126+
const nameAccountKey = await getNameAccountKey(
127+
hashedName,
128+
nameClass,
129+
parentName
130+
);
131+
return nameAccountKey;
132+
};
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
import {
2+
Keypair,
3+
LAMPORTS_PER_SOL,
4+
PublicKey,
5+
SystemProgram,
6+
} from '@solana/web3.js';
7+
import chai, { expect } from 'chai';
8+
import chaiAsPromised from 'chai-as-promised';
9+
10+
import {
11+
createInstruction,
12+
deleteInstruction,
13+
reallocInstruction,
14+
transferInstruction,
15+
updateInstruction,
16+
} from '../../src';
17+
import { Numberu32, Numberu64 } from '../../src/utils';
18+
19+
chai.use(chaiAsPromised);
20+
21+
describe('SplNameService Instructions', () => {
22+
const nameServiceAddress = new PublicKey(
23+
'namesLPneVptA9Z5rqUDD9tMTWEJwofgaYwp8cawRkX'
24+
);
25+
const nameAccountKey = Keypair.generate().publicKey;
26+
const nameOwnerKey = Keypair.generate().publicKey;
27+
const payerKey = Keypair.generate().publicKey;
28+
const nameClassKey = Keypair.generate().publicKey;
29+
const nameParent = Keypair.generate().publicKey;
30+
const nameParentOwner = Keypair.generate().publicKey;
31+
const name = Buffer.from('hello');
32+
33+
it('createInstruction without class and parent name key', () => {
34+
const instruction = createInstruction(
35+
nameServiceAddress,
36+
SystemProgram.programId,
37+
nameAccountKey,
38+
nameOwnerKey,
39+
payerKey,
40+
name,
41+
new Numberu64(LAMPORTS_PER_SOL),
42+
new Numberu64(10)
43+
);
44+
45+
expect(instruction.keys).to.have.length(6);
46+
instruction.keys[0].pubkey.equals(SystemProgram.programId);
47+
instruction.keys[1].pubkey.equals(payerKey);
48+
instruction.keys[2].pubkey.equals(nameAccountKey);
49+
instruction.keys[3].pubkey.equals(nameOwnerKey);
50+
instruction.keys[4].pubkey.equals(new PublicKey(Buffer.alloc(32)));
51+
instruction.keys[5].pubkey.equals(new PublicKey(Buffer.alloc(32)));
52+
});
53+
54+
it('createInstruction with class and parent name key', () => {
55+
const instruction = createInstruction(
56+
nameServiceAddress,
57+
SystemProgram.programId,
58+
nameAccountKey,
59+
nameOwnerKey,
60+
payerKey,
61+
name,
62+
new Numberu64(LAMPORTS_PER_SOL),
63+
new Numberu64(10),
64+
nameClassKey,
65+
nameParent,
66+
nameParentOwner
67+
);
68+
69+
expect(instruction.keys).to.have.length(7);
70+
instruction.keys[0].pubkey.equals(SystemProgram.programId);
71+
instruction.keys[1].pubkey.equals(payerKey);
72+
instruction.keys[2].pubkey.equals(nameAccountKey);
73+
instruction.keys[3].pubkey.equals(nameOwnerKey);
74+
instruction.keys[4].pubkey.equals(nameClassKey);
75+
instruction.keys[5].pubkey.equals(nameParent);
76+
instruction.keys[6].pubkey.equals(nameParentOwner);
77+
});
78+
79+
it('updateInstruction', () => {
80+
const data = Buffer.from('@Dudl');
81+
const instruction = updateInstruction(
82+
nameServiceAddress,
83+
nameAccountKey,
84+
new Numberu32(0),
85+
data,
86+
nameOwnerKey,
87+
undefined
88+
);
89+
90+
expect(instruction.keys).to.have.length(2);
91+
instruction.keys[0].pubkey.equals(nameAccountKey);
92+
instruction.keys[1].pubkey.equals(nameOwnerKey);
93+
});
94+
95+
it('transferInstruction', () => {
96+
const newOwner = Keypair.generate().publicKey;
97+
const instruction = transferInstruction(
98+
nameServiceAddress,
99+
nameAccountKey,
100+
newOwner,
101+
nameOwnerKey
102+
);
103+
104+
expect(instruction.keys).to.have.length(2);
105+
instruction.keys[0].pubkey.equals(nameAccountKey);
106+
instruction.keys[1].pubkey.equals(nameOwnerKey);
107+
});
108+
109+
it('deleteInstruction', () => {
110+
const instruction = deleteInstruction(
111+
nameServiceAddress,
112+
nameAccountKey,
113+
payerKey,
114+
nameOwnerKey
115+
);
116+
117+
expect(instruction.keys).to.have.length(3);
118+
instruction.keys[0].pubkey.equals(nameAccountKey);
119+
instruction.keys[1].pubkey.equals(nameOwnerKey);
120+
instruction.keys[2].pubkey.equals(payerKey);
121+
});
122+
123+
it('reallocInstruction', () => {
124+
const instruction = reallocInstruction(
125+
nameServiceAddress,
126+
SystemProgram.programId,
127+
payerKey,
128+
nameAccountKey,
129+
nameOwnerKey,
130+
new Numberu32(30)
131+
);
132+
133+
expect(instruction.keys).to.have.length(4);
134+
instruction.keys[0].pubkey.equals(SystemProgram.programId);
135+
instruction.keys[1].pubkey.equals(payerKey);
136+
instruction.keys[2].pubkey.equals(nameAccountKey);
137+
instruction.keys[3].pubkey.equals(nameOwnerKey);
138+
});
139+
});

0 commit comments

Comments
 (0)