(wasm) webdriver-based tests for JS/TS apis, update README
This commit is contained in:
99
veilid-wasm/tests/src/VeilidTable.test.ts
Normal file
99
veilid-wasm/tests/src/VeilidTable.test.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
import { expect } from '@wdio/globals';
|
||||
|
||||
import {
|
||||
veilidCoreInitConfig,
|
||||
veilidCoreStartupConfig,
|
||||
} from './utils/veilid-config';
|
||||
|
||||
import { VeilidTableDB, veilidClient } from 'veilid-wasm';
|
||||
import { marshall, unmarshall } from './utils/marshalling-utils';
|
||||
|
||||
const TABLE_NAME = 'some-table';
|
||||
const TABLE_COLS = 1;
|
||||
|
||||
describe('VeilidTable', () => {
|
||||
before('veilid startup', async () => {
|
||||
veilidClient.initializeCore(veilidCoreInitConfig);
|
||||
await veilidClient.startupCore((_update) => {
|
||||
// if (_update.kind === 'Log') {
|
||||
// console.log(_update.message);
|
||||
// }
|
||||
}, JSON.stringify(veilidCoreStartupConfig));
|
||||
});
|
||||
|
||||
after('veilid shutdown', async () => {
|
||||
await veilidClient.shutdownCore();
|
||||
});
|
||||
|
||||
it('should open and close a table', async () => {
|
||||
const table = new VeilidTableDB(TABLE_NAME, TABLE_COLS);
|
||||
await table.openTable();
|
||||
|
||||
const keys = await table.getKeys(0);
|
||||
expect(keys.length).toBe(0);
|
||||
|
||||
table.free();
|
||||
});
|
||||
|
||||
describe('table operations', () => {
|
||||
let table: VeilidTableDB;
|
||||
|
||||
before('create table', async () => {
|
||||
table = new VeilidTableDB(TABLE_NAME, TABLE_COLS);
|
||||
await table.openTable();
|
||||
});
|
||||
|
||||
after('free table', async () => {
|
||||
table.free();
|
||||
});
|
||||
|
||||
it('should have no keys', async () => {
|
||||
const keys = await table.getKeys(0);
|
||||
expect(keys.length).toBe(0);
|
||||
});
|
||||
|
||||
describe('store/load', () => {
|
||||
const key = 'test-key with unicode 🚀';
|
||||
const value = 'test value with unicode 🚀';
|
||||
|
||||
it('should store value', async () => {
|
||||
await table.store(0, marshall(key), marshall(value));
|
||||
});
|
||||
|
||||
it('should load value', async () => {
|
||||
const storedValue = await table.load(0, marshall(key));
|
||||
expect(storedValue).toBeDefined();
|
||||
expect(unmarshall(storedValue!)).toBe(value);
|
||||
});
|
||||
|
||||
it('should have key in list of keys', async () => {
|
||||
const keys = await table.getKeys(0);
|
||||
const decodedKeys = keys.map(unmarshall);
|
||||
expect(decodedKeys).toEqual([key]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('transactions', () => {
|
||||
it('should commit a transaction', async () => {
|
||||
let transaction = await table.createTransaction();
|
||||
|
||||
const key = 'tranaction-key🔥';
|
||||
const first = 'first🅱';
|
||||
const second = 'second✔';
|
||||
const third = 'third📢';
|
||||
|
||||
transaction.store(0, marshall(key), marshall(first));
|
||||
transaction.store(0, marshall(key), marshall(second));
|
||||
transaction.store(0, marshall(key), marshall(third));
|
||||
|
||||
await transaction.commit();
|
||||
|
||||
const storedValue = await table.load(0, marshall(key));
|
||||
expect(storedValue).toBeDefined();
|
||||
expect(unmarshall(storedValue!)).toBe(third);
|
||||
|
||||
transaction.free();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
45
veilid-wasm/tests/src/utils/marshalling-utils.ts
Normal file
45
veilid-wasm/tests/src/utils/marshalling-utils.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
// TextEncoder/TextDecoder are used to solve for "The Unicode Problem" https://stackoverflow.com/a/30106551
|
||||
|
||||
export function marshall(data: string) {
|
||||
const byteString = bytesToString(new TextEncoder().encode(data));
|
||||
return base64UrlEncode(byteString);
|
||||
}
|
||||
|
||||
export function unmarshall(b64: string) {
|
||||
const byteString = base64UrlDecode(b64);
|
||||
return new TextDecoder().decode(stringToBytes(byteString));
|
||||
}
|
||||
|
||||
function base64UrlEncode(data: string) {
|
||||
return removeBase64Padding(btoa(data));
|
||||
}
|
||||
|
||||
function base64UrlDecode(b64: string) {
|
||||
return atob(addBase64Padding(b64));
|
||||
}
|
||||
|
||||
function removeBase64Padding(b64: string) {
|
||||
// URL encode characters, and remove `=` padding.
|
||||
return b64.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_');
|
||||
}
|
||||
|
||||
function addBase64Padding(b64: string) {
|
||||
// URL decode characters
|
||||
b64 = b64.replace(/-/g, '+').replace(/_/g, '/');
|
||||
// Add base64 padding characters (`=`)
|
||||
const rem = b64.length % 4;
|
||||
if (rem === 2) {
|
||||
return `${b64}==`;
|
||||
} else if (rem === 3) {
|
||||
return `${b64}=`;
|
||||
}
|
||||
return b64;
|
||||
}
|
||||
|
||||
function stringToBytes(binString: string) {
|
||||
return Uint8Array.from(binString as any, (m) => (m as any).codePointAt(0));
|
||||
}
|
||||
|
||||
function bytesToString(bytes: Uint8Array) {
|
||||
return Array.from(bytes, (x: number) => String.fromCodePoint(x)).join('');
|
||||
}
|
140
veilid-wasm/tests/src/utils/veilid-config.ts
Normal file
140
veilid-wasm/tests/src/utils/veilid-config.ts
Normal file
@@ -0,0 +1,140 @@
|
||||
import type { VeilidWASMConfig } from 'veilid-wasm';
|
||||
|
||||
export const veilidCoreInitConfig: VeilidWASMConfig = {
|
||||
logging: {
|
||||
api: {
|
||||
enabled: true,
|
||||
level: 'Debug',
|
||||
},
|
||||
performance: {
|
||||
enabled: false,
|
||||
level: 'Info',
|
||||
logs_in_timings: false,
|
||||
logs_in_console: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const veilidCoreStartupConfig = {
|
||||
program_name: 'veilid-wasm-test',
|
||||
namespace: '',
|
||||
capabilities: {
|
||||
disable: [],
|
||||
},
|
||||
protected_store: {
|
||||
allow_insecure_fallback: true,
|
||||
always_use_insecure_storage: true,
|
||||
directory: '',
|
||||
delete: false,
|
||||
device_encryption_key_password: 'some-user-secret-value',
|
||||
// "new_device_encryption_key_password": "an-updated-user-secret-value"
|
||||
},
|
||||
table_store: {
|
||||
directory: '',
|
||||
delete: false,
|
||||
},
|
||||
block_store: {
|
||||
directory: '',
|
||||
delete: false,
|
||||
},
|
||||
network: {
|
||||
connection_initial_timeout_ms: 2000,
|
||||
connection_inactivity_timeout_ms: 60000,
|
||||
max_connections_per_ip4: 32,
|
||||
max_connections_per_ip6_prefix: 32,
|
||||
max_connections_per_ip6_prefix_size: 56,
|
||||
max_connection_frequency_per_min: 128,
|
||||
client_whitelist_timeout_ms: 300000,
|
||||
reverse_connection_receipt_time_ms: 5000,
|
||||
hole_punch_receipt_time_ms: 5000,
|
||||
network_key_password: '',
|
||||
disable_capabilites: [],
|
||||
routing_table: {
|
||||
node_id: [],
|
||||
node_id_secret: [],
|
||||
bootstrap: ['ws://bootstrap.veilid.net:5150/ws'],
|
||||
limit_over_attached: 64,
|
||||
limit_fully_attached: 32,
|
||||
limit_attached_strong: 16,
|
||||
limit_attached_good: 8,
|
||||
limit_attached_weak: 4,
|
||||
},
|
||||
rpc: {
|
||||
concurrency: 0,
|
||||
queue_size: 1024,
|
||||
max_timestamp_behind_ms: 10000,
|
||||
max_timestamp_ahead_ms: 10000,
|
||||
timeout_ms: 5000,
|
||||
max_route_hop_count: 4,
|
||||
default_route_hop_count: 1,
|
||||
},
|
||||
dht: {
|
||||
max_find_node_count: 20,
|
||||
resolve_node_timeout_ms: 10000,
|
||||
resolve_node_count: 1,
|
||||
resolve_node_fanout: 4,
|
||||
get_value_timeout_ms: 10000,
|
||||
get_value_count: 3,
|
||||
get_value_fanout: 4,
|
||||
set_value_timeout_ms: 10000,
|
||||
set_value_count: 5,
|
||||
set_value_fanout: 4,
|
||||
min_peer_count: 20,
|
||||
min_peer_refresh_time_ms: 60000,
|
||||
validate_dial_info_receipt_time_ms: 2000,
|
||||
local_subkey_cache_size: 128,
|
||||
local_max_subkey_cache_memory_mb: 256,
|
||||
remote_subkey_cache_size: 1024,
|
||||
remote_max_records: 65536,
|
||||
remote_max_subkey_cache_memory_mb: 256,
|
||||
remote_max_storage_space_mb: 0,
|
||||
},
|
||||
upnp: true,
|
||||
detect_address_changes: true,
|
||||
restricted_nat_retries: 0,
|
||||
tls: {
|
||||
certificate_path: '',
|
||||
private_key_path: '',
|
||||
connection_initial_timeout_ms: 2000,
|
||||
},
|
||||
application: {
|
||||
https: {
|
||||
enabled: false,
|
||||
listen_address: ':5150',
|
||||
path: 'app',
|
||||
},
|
||||
http: {
|
||||
enabled: false,
|
||||
listen_address: ':5150',
|
||||
path: 'app',
|
||||
},
|
||||
},
|
||||
protocol: {
|
||||
udp: {
|
||||
enabled: false,
|
||||
socket_pool_size: 0,
|
||||
listen_address: '',
|
||||
},
|
||||
tcp: {
|
||||
connect: false,
|
||||
listen: false,
|
||||
max_connections: 32,
|
||||
listen_address: '',
|
||||
},
|
||||
ws: {
|
||||
connect: true,
|
||||
listen: true,
|
||||
max_connections: 16,
|
||||
listen_address: ':5150',
|
||||
path: 'ws',
|
||||
},
|
||||
wss: {
|
||||
connect: true,
|
||||
listen: false,
|
||||
max_connections: 16,
|
||||
listen_address: '',
|
||||
path: 'ws',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
3
veilid-wasm/tests/src/utils/wait-utils.ts
Normal file
3
veilid-wasm/tests/src/utils/wait-utils.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export const waitForMs = (milliseconds: number) => {
|
||||
return new Promise((resolve) => setTimeout(resolve, milliseconds));
|
||||
};
|
59
veilid-wasm/tests/src/veilidClient.test.ts
Normal file
59
veilid-wasm/tests/src/veilidClient.test.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { expect } from '@wdio/globals';
|
||||
|
||||
import {
|
||||
veilidCoreInitConfig,
|
||||
veilidCoreStartupConfig,
|
||||
} from './utils/veilid-config';
|
||||
|
||||
import { VeilidState, veilidClient } from 'veilid-wasm';
|
||||
import { waitForMs } from './utils/wait-utils';
|
||||
|
||||
describe('veilidClient', () => {
|
||||
before('veilid startup', async () => {
|
||||
veilidClient.initializeCore(veilidCoreInitConfig);
|
||||
await veilidClient.startupCore((_update) => {
|
||||
// if (_update.kind === 'Log') {
|
||||
// console.log(_update.message);
|
||||
// }
|
||||
}, JSON.stringify(veilidCoreStartupConfig));
|
||||
});
|
||||
|
||||
after('veilid shutdown', async () => {
|
||||
await veilidClient.shutdownCore();
|
||||
});
|
||||
|
||||
it('should print version', async () => {
|
||||
const version = veilidClient.versionString();
|
||||
expect(typeof version).toBe('string');
|
||||
expect(version.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('should attach and detach', async () => {
|
||||
await veilidClient.attach();
|
||||
await waitForMs(2000);
|
||||
await veilidClient.detach();
|
||||
});
|
||||
|
||||
describe('kitchen sink', () => {
|
||||
before('attach', async () => {
|
||||
await veilidClient.attach();
|
||||
await waitForMs(2000);
|
||||
});
|
||||
after('detach', () => veilidClient.detach());
|
||||
|
||||
let state: VeilidState;
|
||||
|
||||
it('should get state', async () => {
|
||||
state = await veilidClient.getState();
|
||||
expect(state.attachment).toBeDefined();
|
||||
expect(state.config.config).toBeDefined();
|
||||
expect(state.network).toBeDefined();
|
||||
});
|
||||
|
||||
it('should call debug command', async () => {
|
||||
const response = await veilidClient.debug('txtrecord');
|
||||
expect(response).toBeDefined();
|
||||
expect(response.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
});
|
38
veilid-wasm/tests/src/veilidCrypto.test.ts
Normal file
38
veilid-wasm/tests/src/veilidCrypto.test.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { expect } from '@wdio/globals';
|
||||
|
||||
import {
|
||||
veilidCoreInitConfig,
|
||||
veilidCoreStartupConfig,
|
||||
} from './utils/veilid-config';
|
||||
|
||||
import { veilidClient, veilidCrypto } from 'veilid-wasm';
|
||||
|
||||
describe('veilidCrypto', () => {
|
||||
before('veilid startup', async () => {
|
||||
veilidClient.initializeCore(veilidCoreInitConfig);
|
||||
await veilidClient.startupCore((_update) => {
|
||||
// if (_update.kind === 'Log') {
|
||||
// console.log(_update.message);
|
||||
// }
|
||||
}, JSON.stringify(veilidCoreStartupConfig));
|
||||
});
|
||||
|
||||
after('veilid shutdown', async () => {
|
||||
await veilidClient.shutdownCore();
|
||||
});
|
||||
|
||||
it('should list crypto kinds', () => {
|
||||
const kinds = veilidCrypto.validCryptoKinds();
|
||||
const bestKind = veilidCrypto.bestCryptoKind();
|
||||
|
||||
expect(typeof bestKind).toBe('string');
|
||||
expect(kinds.includes(bestKind)).toBe(true);
|
||||
});
|
||||
|
||||
it('should generate key pair', async () => {
|
||||
const bestKind = veilidCrypto.bestCryptoKind();
|
||||
const keypair = veilidCrypto.generateKeyPair(bestKind);
|
||||
expect(typeof keypair).toBe('string');
|
||||
// TODO: fix TypeScript return type of generateKeyPair to return string instead of KeyPair
|
||||
});
|
||||
});
|
Reference in New Issue
Block a user