Initial Commit
This commit is contained in:
88
tests/client.test.ts
Normal file
88
tests/client.test.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* Tests for HTTP client with HMAC authentication
|
||||
*/
|
||||
|
||||
import * as crypto from 'crypto';
|
||||
import { DragonchainClient } from '../src/client';
|
||||
|
||||
describe('DragonchainClient', () => {
|
||||
const testConfig = {
|
||||
publicId: 'test-public-id',
|
||||
authKeyId: 'test-auth-key-id',
|
||||
authKey: 'test-auth-key',
|
||||
baseURL: 'https://test.dragonchain.com',
|
||||
};
|
||||
|
||||
let client: DragonchainClient;
|
||||
|
||||
beforeEach(() => {
|
||||
client = new DragonchainClient(testConfig);
|
||||
});
|
||||
|
||||
describe('constructor', () => {
|
||||
it('should create a client with correct configuration', () => {
|
||||
expect(client).toBeDefined();
|
||||
expect(client.get).toBeDefined();
|
||||
});
|
||||
|
||||
it('should remove trailing slash from baseURL', () => {
|
||||
const clientWithSlash = new DragonchainClient({
|
||||
...testConfig,
|
||||
baseURL: 'https://test.dragonchain.com/',
|
||||
});
|
||||
expect(clientWithSlash).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('HMAC authentication', () => {
|
||||
it('should generate correct HMAC signature', () => {
|
||||
// Test HMAC generation by creating a mock scenario
|
||||
const method = 'POST';
|
||||
const path = '/api/v1/transaction';
|
||||
const timestamp = '1234567890';
|
||||
const contentType = 'application/json';
|
||||
const body = Buffer.from(JSON.stringify({ test: 'data' }));
|
||||
|
||||
// Calculate expected values
|
||||
const contentHash = crypto.createHash('sha256').update(body).digest('base64');
|
||||
const message = [
|
||||
method.toUpperCase(),
|
||||
path,
|
||||
testConfig.publicId,
|
||||
timestamp,
|
||||
contentType,
|
||||
contentHash,
|
||||
].join('\n');
|
||||
|
||||
const expectedHmac = crypto
|
||||
.createHmac('sha256', testConfig.authKey)
|
||||
.update(message)
|
||||
.digest('base64');
|
||||
|
||||
// The auth header should follow the format: DC1-HMAC-SHA256 {authKeyId}:{signature}
|
||||
const expectedAuthHeader = `DC1-HMAC-SHA256 ${testConfig.authKeyId}:${expectedHmac}`;
|
||||
|
||||
// We can't directly test the private method, but we verify the format is correct
|
||||
expect(expectedAuthHeader).toContain('DC1-HMAC-SHA256');
|
||||
expect(expectedAuthHeader).toContain(testConfig.authKeyId);
|
||||
});
|
||||
});
|
||||
|
||||
describe('request methods', () => {
|
||||
it('should have get method', () => {
|
||||
expect(typeof client.get).toBe('function');
|
||||
});
|
||||
|
||||
it('should have post method', () => {
|
||||
expect(typeof client.post).toBe('function');
|
||||
});
|
||||
|
||||
it('should have put method', () => {
|
||||
expect(typeof client.put).toBe('function');
|
||||
});
|
||||
|
||||
it('should have delete method', () => {
|
||||
expect(typeof client.delete).toBe('function');
|
||||
});
|
||||
});
|
||||
});
|
||||
105
tests/credentials.test.ts
Normal file
105
tests/credentials.test.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* Tests for credentials module
|
||||
*/
|
||||
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { loadConfig, loadConfigFromString, getDefaultChain, getChainByPublicId, listChains } from '../src/credentials';
|
||||
|
||||
describe('Credentials Module', () => {
|
||||
const testYaml = `
|
||||
default: test-chain-id
|
||||
chains:
|
||||
- name: test-chain
|
||||
publicId: test-chain-id
|
||||
authKeyId: test-auth-key-id
|
||||
authKey: test-auth-key
|
||||
endpoint: https://test.dragonchain.com
|
||||
- name: another-chain
|
||||
publicId: another-chain-id
|
||||
authKeyId: another-auth-key-id
|
||||
authKey: another-auth-key
|
||||
endpoint: https://another.dragonchain.com
|
||||
`;
|
||||
|
||||
describe('loadConfigFromString', () => {
|
||||
it('should load config from YAML string', () => {
|
||||
const config = loadConfigFromString(testYaml);
|
||||
expect(config.default).toBe('test-chain-id');
|
||||
expect(config.chains).toHaveLength(2);
|
||||
expect(config.chains[0].name).toBe('test-chain');
|
||||
});
|
||||
|
||||
it('should throw error for invalid YAML', () => {
|
||||
expect(() => loadConfigFromString('invalid: [yaml')).toThrow();
|
||||
});
|
||||
|
||||
it('should throw error for missing chains array', () => {
|
||||
expect(() => loadConfigFromString('default: test')).toThrow('Invalid config: missing or invalid chains array');
|
||||
});
|
||||
});
|
||||
|
||||
describe('loadConfig', () => {
|
||||
const testConfigPath = path.join(__dirname, 'test-config.yaml');
|
||||
|
||||
beforeEach(() => {
|
||||
fs.writeFileSync(testConfigPath, testYaml);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
if (fs.existsSync(testConfigPath)) {
|
||||
fs.unlinkSync(testConfigPath);
|
||||
}
|
||||
});
|
||||
|
||||
it('should load config from file', () => {
|
||||
const config = loadConfig(testConfigPath);
|
||||
expect(config.default).toBe('test-chain-id');
|
||||
expect(config.chains).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('should throw error for non-existent file', () => {
|
||||
expect(() => loadConfig('/non/existent/path.yaml')).toThrow('Config file not found');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getDefaultChain', () => {
|
||||
it('should return the default chain', () => {
|
||||
const config = loadConfigFromString(testYaml);
|
||||
const defaultChain = getDefaultChain(config);
|
||||
expect(defaultChain).toBeDefined();
|
||||
expect(defaultChain?.name).toBe('test-chain');
|
||||
expect(defaultChain?.publicId).toBe('test-chain-id');
|
||||
});
|
||||
|
||||
it('should return undefined if default not found', () => {
|
||||
const config = loadConfigFromString(testYaml);
|
||||
config.default = 'non-existent';
|
||||
const defaultChain = getDefaultChain(config);
|
||||
expect(defaultChain).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getChainByPublicId', () => {
|
||||
it('should return chain by public ID', () => {
|
||||
const config = loadConfigFromString(testYaml);
|
||||
const chain = getChainByPublicId(config, 'another-chain-id');
|
||||
expect(chain).toBeDefined();
|
||||
expect(chain?.name).toBe('another-chain');
|
||||
});
|
||||
|
||||
it('should return undefined if chain not found', () => {
|
||||
const config = loadConfigFromString(testYaml);
|
||||
const chain = getChainByPublicId(config, 'non-existent');
|
||||
expect(chain).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('listChains', () => {
|
||||
it('should return all chain names', () => {
|
||||
const config = loadConfigFromString(testYaml);
|
||||
const names = listChains(config);
|
||||
expect(names).toEqual(['test-chain', 'another-chain']);
|
||||
});
|
||||
});
|
||||
});
|
||||
91
tests/sdk.test.ts
Normal file
91
tests/sdk.test.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* Tests for main SDK
|
||||
*/
|
||||
|
||||
import { DragonchainSDK } from '../src/index';
|
||||
|
||||
describe('DragonchainSDK', () => {
|
||||
const testConfig = {
|
||||
publicId: 'test-public-id',
|
||||
authKeyId: 'test-auth-key-id',
|
||||
authKey: 'test-auth-key',
|
||||
baseURL: 'https://test.dragonchain.com',
|
||||
};
|
||||
|
||||
let sdk: DragonchainSDK;
|
||||
|
||||
beforeEach(() => {
|
||||
sdk = new DragonchainSDK(
|
||||
testConfig.publicId,
|
||||
testConfig.authKeyId,
|
||||
testConfig.authKey,
|
||||
testConfig.baseURL
|
||||
);
|
||||
});
|
||||
|
||||
describe('initialization', () => {
|
||||
it('should create SDK instance', () => {
|
||||
expect(sdk).toBeDefined();
|
||||
});
|
||||
|
||||
it('should initialize all client modules', () => {
|
||||
expect(sdk.transaction).toBeDefined();
|
||||
expect(sdk.transactionType).toBeDefined();
|
||||
expect(sdk.contract).toBeDefined();
|
||||
expect(sdk.block).toBeDefined();
|
||||
expect(sdk.system).toBeDefined();
|
||||
});
|
||||
|
||||
it('should provide access to underlying client', () => {
|
||||
const client = sdk.getClient();
|
||||
expect(client).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('module methods', () => {
|
||||
it('should have transaction module with correct methods', () => {
|
||||
expect(typeof sdk.transaction.create).toBe('function');
|
||||
expect(typeof sdk.transaction.createBulk).toBe('function');
|
||||
expect(typeof sdk.transaction.get).toBe('function');
|
||||
expect(typeof sdk.transaction.list).toBe('function');
|
||||
});
|
||||
|
||||
it('should have transactionType module with correct methods', () => {
|
||||
expect(typeof sdk.transactionType.create).toBe('function');
|
||||
expect(typeof sdk.transactionType.get).toBe('function');
|
||||
expect(typeof sdk.transactionType.list).toBe('function');
|
||||
expect(typeof sdk.transactionType.delete).toBe('function');
|
||||
});
|
||||
|
||||
it('should have contract module with correct methods', () => {
|
||||
expect(typeof sdk.contract.create).toBe('function');
|
||||
expect(typeof sdk.contract.get).toBe('function');
|
||||
expect(typeof sdk.contract.list).toBe('function');
|
||||
expect(typeof sdk.contract.update).toBe('function');
|
||||
expect(typeof sdk.contract.upload).toBe('function');
|
||||
expect(typeof sdk.contract.delete).toBe('function');
|
||||
});
|
||||
|
||||
it('should have block module with correct methods', () => {
|
||||
expect(typeof sdk.block.get).toBe('function');
|
||||
});
|
||||
|
||||
it('should have system module with correct methods', () => {
|
||||
expect(typeof sdk.system.health).toBe('function');
|
||||
expect(typeof sdk.system.status).toBe('function');
|
||||
});
|
||||
});
|
||||
|
||||
describe('timeout configuration', () => {
|
||||
it('should accept custom timeout', () => {
|
||||
const customSdk = new DragonchainSDK(
|
||||
testConfig.publicId,
|
||||
testConfig.authKeyId,
|
||||
testConfig.authKey,
|
||||
testConfig.baseURL,
|
||||
60000
|
||||
);
|
||||
expect(customSdk).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user