Skip to content

Commit 9aa4460

Browse files
committed
revert auto cleanup + fix init cli profile + unit tests: init harness & fund account
1 parent 9bf7cac commit 9aa4460

File tree

7 files changed

+341
-67
lines changed

7 files changed

+341
-67
lines changed

packages/forklift/package-lock.json

Lines changed: 26 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/forklift/package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717
},
1818
"dependencies": {
1919
"@aptos-labs/ts-sdk": "^4.0.0",
20+
"@types/node": "^24.3.1",
21+
"@types/js-yaml": "^4.0.9",
22+
"js-yaml": "^4.1.1",
2023
"ts-node": "^10.9.2",
21-
"typescript": "^5.9.2",
22-
"@types/node": "^24.3.1"
24+
"typescript": "^5.9.2"
2325
}
2426
}

packages/forklift/src/harness.ts

Lines changed: 126 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,21 @@
11
import { spawnSync } from "child_process";
2-
import { mkdtempSync, rmSync } from "fs";
2+
import {
3+
mkdtempSync,
4+
rmSync,
5+
readFileSync,
6+
writeFileSync,
7+
existsSync,
8+
mkdirSync,
9+
} from "fs";
310
import { join } from "path";
411
import { tmpdir } from "os";
5-
import { Ed25519PrivateKey } from "@aptos-labs/ts-sdk";
12+
import {
13+
Account,
14+
Ed25519PrivateKey,
15+
PrivateKey,
16+
PrivateKeyVariants,
17+
} from "@aptos-labs/ts-sdk";
18+
import yaml from "js-yaml";
619

720
const APTOS_BINARY = "aptos";
821

@@ -45,7 +58,7 @@ export function runCommand(
4558

4659
if (result.status !== 0) {
4760
throw new Error(
48-
`Process exited with code ${result.status}: ${result.stderr}`,
61+
`Process exited with code ${result.status}.\n\nStdout:\n${result.stdout}\nStderr:\n${result.stderr}`,
4962
);
5063
}
5164

@@ -134,51 +147,71 @@ class TestHarness {
134147
this.init_cli_profile("default");
135148
this.init_session(options);
136149
this.fundAccount("default", 10000000000 /* 100 APT */);
137-
138-
// Auto-cleanup if running in Jest, Vitest, Jasmine, or Mocha
139-
//
140-
// Jest, Vitest, and Jasmine use `afterAll`, while Mocha uses `after`.
141-
// We check for both and register the cleanup hook accordingly.
142-
const globalAny = globalThis as any;
143-
if (typeof globalAny.afterAll === "function") {
144-
globalAny.afterAll(() => this.cleanup());
145-
} else if (typeof globalAny.after === "function") {
146-
globalAny.after(() => this.cleanup());
147-
}
148150
}
149151

150152
/**
151153
* Initialize the Aptos CLI profile in the temporary directory.
152-
*
153154
* If a private key is not provided, a random one will be generated.
154155
*
156+
* This is currently done by appending a new profile to the CLI's config file
157+
* (`.aptos/config.yaml`) as opposed to running the CLI's `init` command, in order to
158+
* avoid unnecessary communication with the actual network.
159+
*
155160
* @throws Error if the initialization fails.
156161
*/
157162
init_cli_profile(profile_name: string, privateKey?: string): void {
158-
const pk = privateKey
159-
? privateKey
160-
: Ed25519PrivateKey.generate().toHexString();
163+
const privKey = privateKey
164+
? new Ed25519PrivateKey(
165+
PrivateKey.formatPrivateKey(privateKey, PrivateKeyVariants.Ed25519),
166+
)
167+
: Ed25519PrivateKey.generate();
168+
169+
const pubKey = privKey.publicKey();
170+
const addr = Account.fromPrivateKey({
171+
privateKey: privKey,
172+
}).accountAddress.toString();
173+
174+
let profile = {
175+
network: "Local",
176+
rest_url: "https://fullnode.dummynetwork.aptoslabs.com",
177+
account: addr,
178+
private_key: privKey.toAIP80String(),
179+
public_key: "ed25519-pub-" + pubKey.toString(),
180+
};
181+
182+
const aptosDir = join(this.tempDir, ".aptos");
183+
const configPath = join(aptosDir, "config.yaml");
184+
185+
if (!existsSync(aptosDir)) {
186+
mkdirSync(aptosDir, { recursive: true });
187+
}
161188

162-
// prettier-ignore
163-
const res = runCommand(
164-
APTOS_BINARY,
165-
[
166-
"init",
167-
"--profile", profile_name,
168-
"--network", "mainnet",
169-
"--skip-faucet",
170-
"--private-key", pk,
171-
],
172-
{
173-
cwd: this.tempDir,
174-
},
175-
);
189+
let config: any = { profiles: {} };
190+
if (existsSync(configPath)) {
191+
try {
192+
const fileContent = readFileSync(configPath, "utf8");
193+
config = yaml.load(fileContent) || { profiles: {} };
194+
if (!config.profiles) {
195+
config.profiles = {};
196+
}
197+
} catch (e) {
198+
throw new Error(
199+
`Failed to parse existing config at ${configPath}: ${e}`,
200+
);
201+
}
202+
}
176203

177-
if (!res || res.Result !== "Success") {
204+
if (config.profiles[profile_name]) {
178205
throw new Error(
179-
`aptos init failed: expected Result = Success, got ${JSON.stringify(res)}`,
206+
`Profile ${profile_name} already exists in ${configPath}`,
180207
);
181208
}
209+
config.profiles[profile_name] = profile;
210+
211+
writeFileSync(
212+
configPath,
213+
yaml.dump(config, { indent: 2, sortKeys: true, lineWidth: 120 }),
214+
);
182215
}
183216

184217
/**
@@ -222,7 +255,7 @@ class TestHarness {
222255
*
223256
* @throws Error if the funding operation fails
224257
*/
225-
fundAccount(account: string, amount: number): void {
258+
fundAccount(account: string, amount: number | bigint | string): void {
226259
// prettier-ignore
227260
const res = runCommand(
228261
APTOS_BINARY,
@@ -365,6 +398,64 @@ class TestHarness {
365398
return res;
366399
}
367400

401+
/**
402+
* Views a resource group from the simulation session.
403+
*
404+
* @param account The account address or profile name
405+
* @param resourceGroup The resource group tag (e.g. 0x1::object::ObjectGroup)
406+
* @param derivedObjectAddress Optional address to derive an object address from
407+
* @returns The parsed JSON output
408+
*/
409+
viewResourceGroup(
410+
account: string,
411+
resourceGroup: string,
412+
derivedObjectAddress?: string,
413+
): any {
414+
const args = [
415+
"move",
416+
"sim",
417+
"view-resource-group",
418+
"--session",
419+
this.getSessionPath(),
420+
"--account",
421+
account,
422+
"--resource-group",
423+
resourceGroup,
424+
];
425+
426+
if (derivedObjectAddress) {
427+
args.push("--derived-object-address", derivedObjectAddress);
428+
}
429+
430+
return runCommand(APTOS_BINARY, args, { cwd: this.tempDir });
431+
}
432+
433+
/**
434+
* Gets the APT balance from the Fungible Store for a given account.
435+
*
436+
* Uses the primary store derived from the account and the APT metadata address (0xA).
437+
*
438+
* @param account The account address or profile name
439+
* @returns The balance as a bigint
440+
*/
441+
getAPTBalanceFungibleStore(account: string): bigint {
442+
const res = this.viewResourceGroup(
443+
account,
444+
"0x1::object::ObjectGroup",
445+
"0xA",
446+
);
447+
448+
if (
449+
!res ||
450+
!res.Result ||
451+
!res.Result["0x1::fungible_asset::FungibleStore"]
452+
) {
453+
return BigInt(0);
454+
}
455+
456+
return BigInt(res.Result["0x1::fungible_asset::FungibleStore"].balance);
457+
}
458+
368459
cleanup(): void {
369460
try {
370461
rmSync(this.tempDir, { recursive: true, force: true });

packages/testsuite/package-lock.json

Lines changed: 4 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/testsuite/src/tests/fund_transfer_and_view_seq_num.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ import { TestHarness, assertTxnSuccess } from "forklift";
33
describe("fund, transfer, and view sequence number", () => {
44
let harness: TestHarness = new TestHarness();
55

6+
afterAll(() => {
7+
harness.cleanup();
8+
});
9+
610
it("fund account", () => {
711
harness.fundAccount("default", 100000000 /* 1 APT */);
812
});

packages/testsuite/src/tests/publish_set_and_view_message.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ import * as path from "path";
44
describe("publish, set message, and view message", () => {
55
let harness: TestHarness = new TestHarness();
66

7+
afterAll(() => {
8+
harness.cleanup();
9+
});
10+
711
it("publish package", () => {
812
const packageDir = path.join(__dirname, "../../move_packages/message");
913
const publishRes = harness.publishPackage({

0 commit comments

Comments
 (0)