Skip to content

Commit

Permalink
refactor(experimental): add unit tests for getAccountInfo RPC method (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
mcintyre94 authored Jul 7, 2023
1 parent 49ed817 commit 3d43623
Show file tree
Hide file tree
Showing 4 changed files with 234 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { createSolanaRpcApi } from './rpc-methods';
export const ALLOWED_NUMERIC_KEYPATHS: Partial<
Record<keyof ReturnType<typeof createSolanaRpcApi>, readonly KeyPath[]>
> = {
getAccountInfo: [['value', 'data', 'parsed', 'info', 'stake', 'delegation', 'warmupCooldownRate']],
getBlockTime: [[]],
getInflationReward: [[KEYPATH_WILDCARD, 'commission']],
getRecentPerformanceSamples: [[KEYPATH_WILDCARD, 'samplePeriodSecs']],
Expand Down
207 changes: 207 additions & 0 deletions packages/rpc-core/src/rpc-methods/__tests__/get-account-info-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
import { Base58EncodedAddress } from '@solana/keys';
import { createHttpTransport, createJsonRpc } from '@solana/rpc-transport';
import type { SolanaJsonRpcErrorCode } from '@solana/rpc-transport/dist/types/json-rpc-errors';
import type { Rpc } from '@solana/rpc-transport/dist/types/json-rpc-types';
import fetchMock from 'jest-fetch-mock-fork';

import { Commitment } from '../common';
import { createSolanaRpcApi, SolanaRpcMethods } from '../index';

describe('getAccountInfo', () => {
let rpc: Rpc<SolanaRpcMethods>;
beforeEach(() => {
fetchMock.resetMocks();
fetchMock.dontMock();
rpc = createJsonRpc<SolanaRpcMethods>({
api: createSolanaRpcApi(),
transport: createHttpTransport({ url: 'http://127.0.0.1:8899' }),
});
});

(['confirmed', 'finalized', 'processed'] as Commitment[]).forEach(commitment => {
describe(`when called with \`${commitment}\` commitment`, () => {
it('returns account info', async () => {
expect.assertions(1);
// See scripts/fixtures/GQE2yjns7SKKuMc89tveBDpzYHwXfeuB2PGAbGaPWc6G.json
const publicKey =
'GQE2yjns7SKKuMc89tveBDpzYHwXfeuB2PGAbGaPWc6G' as Base58EncodedAddress<'GQE2yjns7SKKuMc89tveBDpzYHwXfeuB2PGAbGaPWc6G'>;

const accountInfoPromise = rpc
.getAccountInfo(publicKey, {
commitment,
})
.send();

await expect(accountInfoPromise).resolves.toMatchObject({
value: expect.objectContaining({
data: expect.any(String),
executable: expect.any(Boolean),
lamports: expect.any(BigInt),
owner: expect.any(String),
rentEpoch: expect.any(BigInt),
space: expect.any(BigInt),
}),
});
});
});
});

describe('when called with a `minContextSlot` higher than the highest slot available', () => {
it('throws an error', async () => {
expect.assertions(1);
const publicKey =
'GQE2yjns7SKKuMc89tveBDpzYHwXfeuB2PGAbGaPWc6G' as Base58EncodedAddress<'GQE2yjns7SKKuMc89tveBDpzYHwXfeuB2PGAbGaPWc6G'>;
const sendPromise = rpc
.getAccountInfo(publicKey, {
minContextSlot: 2n ** 63n - 1n, // u64:MAX; safe bet it'll be too high.
})
.send();
await expect(sendPromise).rejects.toMatchObject({
code: -32016 satisfies (typeof SolanaJsonRpcErrorCode)['JSON_RPC_SERVER_ERROR_MIN_CONTEXT_SLOT_NOT_REACHED'],
message: expect.any(String),
name: 'SolanaJsonRpcError',
});
});
});

describe('when called with base58 encoding', () => {
it('returns account info with annotated base58 encoding', async () => {
expect.assertions(1);
// See scripts/fixtures/GQE2yjns7SKKuMc89tveBDpzYHwXfeuB2PGAbGaPWc6G.json
// data is 'test data'
const publicKey =
'GQE2yjns7SKKuMc89tveBDpzYHwXfeuB2PGAbGaPWc6G' as Base58EncodedAddress<'GQE2yjns7SKKuMc89tveBDpzYHwXfeuB2PGAbGaPWc6G'>;

const accountInfo = await rpc
.getAccountInfo(publicKey, {
encoding: 'base58',
})
.send();

expect(accountInfo.value?.data).toStrictEqual(['2Uw1bpnsXxu3e', 'base58']);
});
});

describe('when called with base64 encoding', () => {
it('returns account info with annotated base64 encoding', async () => {
expect.assertions(1);
// See scripts/fixtures/GQE2yjns7SKKuMc89tveBDpzYHwXfeuB2PGAbGaPWc6G.json
// data is 'test data'
const publicKey =
'GQE2yjns7SKKuMc89tveBDpzYHwXfeuB2PGAbGaPWc6G' as Base58EncodedAddress<'GQE2yjns7SKKuMc89tveBDpzYHwXfeuB2PGAbGaPWc6G'>;

const accountInfo = await rpc
.getAccountInfo(publicKey, {
encoding: 'base64',
})
.send();

expect(accountInfo.value?.data).toStrictEqual(['dGVzdCBkYXRh', 'base64']);
});
});

describe('when called with base64+zstd encoding', () => {
it('returns account info with annotated base64+zstd encoding', async () => {
expect.assertions(1);
// See scripts/fixtures/GQE2yjns7SKKuMc89tveBDpzYHwXfeuB2PGAbGaPWc6G.json
// data is 'test data'
const publicKey =
'GQE2yjns7SKKuMc89tveBDpzYHwXfeuB2PGAbGaPWc6G' as Base58EncodedAddress<'GQE2yjns7SKKuMc89tveBDpzYHwXfeuB2PGAbGaPWc6G'>;

const accountInfo = await rpc
.getAccountInfo(publicKey, {
encoding: 'base64+zstd',
})
.send();

expect(accountInfo.value?.data).toStrictEqual(['KLUv/QBYSQAAdGVzdCBkYXRh', 'base64+zstd']);
});
});

describe('when called with jsonParsed encoding', () => {
describe('for an account without parse-able JSON data', () => {
it('falls back to annotated base64', async () => {
expect.assertions(1);
// See scripts/fixtures/GQE2yjns7SKKuMc89tveBDpzYHwXfeuB2PGAbGaPWc6G.json
const publicKey =
'GQE2yjns7SKKuMc89tveBDpzYHwXfeuB2PGAbGaPWc6G' as Base58EncodedAddress<'GQE2yjns7SKKuMc89tveBDpzYHwXfeuB2PGAbGaPWc6G'>;

const accountInfo = await rpc
.getAccountInfo(publicKey, {
encoding: 'jsonParsed',
})
.send();

expect(accountInfo.value?.data).toStrictEqual(['dGVzdCBkYXRh', 'base64']);
});
});

describe('for an account with parse-able JSON data', () => {
it('returns parsed JSON data', async () => {
expect.assertions(1);
//See scripts/fixtures/CSg2vQGbnwWdSyJpwK4i3qGfB6FebaV3xQTx4U1MbixN.json
// This is a base64 encoded stake account
const publicKey =
'CSg2vQGbnwWdSyJpwK4i3qGfB6FebaV3xQTx4U1MbixN' as Base58EncodedAddress<'CSg2vQGbnwWdSyJpwK4i3qGfB6FebaV3xQTx4U1MbixN'>;

const accountInfo = await rpc
.getAccountInfo(publicKey, {
encoding: 'jsonParsed',
})
.send();

expect(accountInfo).toMatchObject({
value: expect.objectContaining({
data: expect.objectContaining({
parsed: expect.objectContaining({
info: {
meta: expect.any(Object),
stake: expect.any(Object),
},
type: 'delegated',
}),
program: 'stake',
space: expect.any(BigInt),
}),
}),
});
});
});
});

describe('when called with no encoding', () => {
it('returns base58 data without an annotation', async () => {
expect.assertions(1);
// See scripts/fixtures/GQE2yjns7SKKuMc89tveBDpzYHwXfeuB2PGAbGaPWc6G.json
// data is 'test data'
const publicKey =
'GQE2yjns7SKKuMc89tveBDpzYHwXfeuB2PGAbGaPWc6G' as Base58EncodedAddress<'GQE2yjns7SKKuMc89tveBDpzYHwXfeuB2PGAbGaPWc6G'>;

const accountInfo = await rpc.getAccountInfo(publicKey, {}).send();

expect(accountInfo.value?.data).toBe('2Uw1bpnsXxu3e');
});
});

describe('when called with a dataSlice', () => {
it('returns the correct slice of the data', async () => {
expect.assertions(1);
// See scripts/fixtures/GQE2yjns7SKKuMc89tveBDpzYHwXfeuB2PGAbGaPWc6G.json
// data is 'test data'
const publicKey =
'GQE2yjns7SKKuMc89tveBDpzYHwXfeuB2PGAbGaPWc6G' as Base58EncodedAddress<'GQE2yjns7SKKuMc89tveBDpzYHwXfeuB2PGAbGaPWc6G'>;

const accountInfo = await rpc
.getAccountInfo(publicKey, {
dataSlice: {
length: 5,
offset: 0,
},
encoding: 'base64',
})
.send();

expect(accountInfo.value?.data).toStrictEqual(['dGVzdCA=', 'base64']);
});
});
});
13 changes: 13 additions & 0 deletions scripts/fixtures/CSg2vQGbnwWdSyJpwK4i3qGfB6FebaV3xQTx4U1MbixN.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"pubkey": "CSg2vQGbnwWdSyJpwK4i3qGfB6FebaV3xQTx4U1MbixN",
"account": {
"data": [
"AgAAAIDVIgAAAAAAIew4IOYWg0ai5I48s8YkuID9Nop6WgtwTQd+Nt/0ybAh7Dgg5haDRqLkjjyzxiS4gP02inpaC3BNB3423/TJsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK0jdm2qTzCVek6Qzfgmj2H4Hw8A6DnJrW76AJ9E7J+m/zB6AAAAAACCAQAAAAAAANcBAAAAAAAAAAAAAAAA0D+ReCEKAAAAAAAAAAA=",
"base64"
],
"executable": false,
"lamports": 10290815,
"owner": "Stake11111111111111111111111111111111111111",
"rentEpoch": 0
}
}
13 changes: 13 additions & 0 deletions scripts/fixtures/GQE2yjns7SKKuMc89tveBDpzYHwXfeuB2PGAbGaPWc6G.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"pubkey": "GQE2yjns7SKKuMc89tveBDpzYHwXfeuB2PGAbGaPWc6G",
"account": {
"lamports": 5000000,
"data": [
"dGVzdCBkYXRh",
"base64"
],
"owner": "11111111111111111111111111111111",
"executable": false,
"rentEpoch": 18446744073709551615
}
}

0 comments on commit 3d43623

Please sign in to comment.