BREAKING CHANGE(tapbundle_serverside): Rename Node-specific tapbundle module to tapbundle_serverside and migrate server-side utilities
This commit is contained in:
98
ts_tapbundle_serverside/classes.tapnodetools.ts
Normal file
98
ts_tapbundle_serverside/classes.tapnodetools.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
import { TestFileProvider } from './classes.testfileprovider.js';
|
||||
import * as plugins from './plugins.js';
|
||||
|
||||
class TapNodeTools {
|
||||
private smartshellInstance: plugins.smartshell.Smartshell;
|
||||
public testFileProvider = new TestFileProvider();
|
||||
|
||||
constructor() {}
|
||||
|
||||
private qenv: plugins.qenv.Qenv;
|
||||
public async getQenv(): Promise<plugins.qenv.Qenv> {
|
||||
this.qenv = this.qenv || new plugins.qenv.Qenv('./', '.nogit/');
|
||||
return this.qenv;
|
||||
}
|
||||
public async getEnvVarOnDemand(envVarNameArg: string): Promise<string> {
|
||||
const qenv = await this.getQenv();
|
||||
return qenv.getEnvVarOnDemand(envVarNameArg);
|
||||
}
|
||||
|
||||
public async runCommand(commandArg: string): Promise<any> {
|
||||
if (!this.smartshellInstance) {
|
||||
this.smartshellInstance = new plugins.smartshell.Smartshell({
|
||||
executor: 'bash',
|
||||
});
|
||||
}
|
||||
const result = await this.smartshellInstance.exec(commandArg);
|
||||
return result;
|
||||
}
|
||||
|
||||
public async createHttpsCert(
|
||||
commonName: string = 'localhost',
|
||||
allowSelfSigned: boolean = true
|
||||
): Promise<{ key: string; cert: string }> {
|
||||
if (allowSelfSigned) {
|
||||
// set node to allow self-signed certificates
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
||||
}
|
||||
|
||||
// Generate a key pair
|
||||
const keys = plugins.smartcrypto.nodeForge.pki.rsa.generateKeyPair(2048);
|
||||
|
||||
// Create a self-signed certificate
|
||||
const cert = plugins.smartcrypto.nodeForge.pki.createCertificate();
|
||||
cert.publicKey = keys.publicKey;
|
||||
cert.serialNumber = '01';
|
||||
cert.validity.notBefore = new Date();
|
||||
cert.validity.notAfter = new Date();
|
||||
cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 1);
|
||||
|
||||
const attrs = [
|
||||
{ name: 'commonName', value: commonName },
|
||||
{ name: 'countryName', value: 'US' },
|
||||
{ shortName: 'ST', value: 'California' },
|
||||
{ name: 'localityName', value: 'San Francisco' },
|
||||
{ name: 'organizationName', value: 'My Company' },
|
||||
{ shortName: 'OU', value: 'Dev' },
|
||||
];
|
||||
cert.setSubject(attrs);
|
||||
cert.setIssuer(attrs);
|
||||
|
||||
// Sign the certificate with its own private key (self-signed)
|
||||
cert.sign(keys.privateKey, plugins.smartcrypto.nodeForge.md.sha256.create());
|
||||
|
||||
// PEM encode the private key and certificate
|
||||
const pemKey = plugins.smartcrypto.nodeForge.pki.privateKeyToPem(keys.privateKey);
|
||||
const pemCert = plugins.smartcrypto.nodeForge.pki.certificateToPem(cert);
|
||||
|
||||
return {
|
||||
key: pemKey,
|
||||
cert: pemCert,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* create and return a smartmongo instance
|
||||
*/
|
||||
public async createSmartmongo() {
|
||||
const smartmongoMod = await import('@push.rocks/smartmongo');
|
||||
const smartmongoInstance = new smartmongoMod.SmartMongo();
|
||||
await smartmongoInstance.start();
|
||||
return smartmongoInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* create and return a smarts3 instance
|
||||
*/
|
||||
public async createSmarts3() {
|
||||
const smarts3Mod = await import('@push.rocks/smarts3');
|
||||
const smarts3Instance = new smarts3Mod.Smarts3({
|
||||
port: 3003,
|
||||
cleanSlate: true,
|
||||
});
|
||||
await smarts3Instance.start();
|
||||
return smarts3Instance;
|
||||
}
|
||||
}
|
||||
|
||||
export const tapNodeTools = new TapNodeTools();
|
||||
20
ts_tapbundle_serverside/classes.testfileprovider.ts
Normal file
20
ts_tapbundle_serverside/classes.testfileprovider.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import * as plugins from './plugins.js';
|
||||
import * as paths from './paths.js';
|
||||
|
||||
export const fileUrls = {
|
||||
dockerAlpineImage: 'https://code.foss.global/testassets/docker/raw/branch/main/alpine.tar',
|
||||
}
|
||||
|
||||
export class TestFileProvider {
|
||||
public async getDockerAlpineImageAsLocalTarball(): Promise<string> {
|
||||
const filePath = plugins.path.join(paths.testFilesDir, 'alpine.tar')
|
||||
// fetch the docker alpine image
|
||||
const response = await plugins.smartrequest.SmartRequest.create()
|
||||
.url(fileUrls.dockerAlpineImage)
|
||||
.get();
|
||||
await plugins.smartfile.fs.ensureDir(paths.testFilesDir);
|
||||
const buffer = Buffer.from(await response.arrayBuffer());
|
||||
await plugins.smartfile.memory.toFs(buffer, filePath);
|
||||
return filePath;
|
||||
}
|
||||
}
|
||||
2
ts_tapbundle_serverside/index.ts
Normal file
2
ts_tapbundle_serverside/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './classes.tapnodetools.js';
|
||||
|
||||
4
ts_tapbundle_serverside/paths.ts
Normal file
4
ts_tapbundle_serverside/paths.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import * as plugins from './plugins.js';
|
||||
|
||||
export const cwd = process.cwd();
|
||||
export const testFilesDir = plugins.path.join(cwd, './.nogit/testfiles/');
|
||||
16
ts_tapbundle_serverside/plugins.ts
Normal file
16
ts_tapbundle_serverside/plugins.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
// node native
|
||||
import * as crypto from 'crypto';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
export { crypto,fs, path, };
|
||||
|
||||
// @push.rocks scope
|
||||
import * as qenv from '@push.rocks/qenv';
|
||||
import * as smartcrypto from '@push.rocks/smartcrypto';
|
||||
import * as smartfile from '@push.rocks/smartfile';
|
||||
import * as smartpath from '@push.rocks/smartpath';
|
||||
import * as smartrequest from '@push.rocks/smartrequest';
|
||||
import * as smartshell from '@push.rocks/smartshell';
|
||||
|
||||
export { qenv, smartcrypto, smartfile, smartpath, smartrequest, smartshell, };
|
||||
369
ts_tapbundle_serverside/readme.md
Normal file
369
ts_tapbundle_serverside/readme.md
Normal file
@@ -0,0 +1,369 @@
|
||||
# @git.zone/tstest/tapbundle_serverside
|
||||
|
||||
> 🔧 Server-side testing utilities for Node.js runtime tests
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
# tapbundle_serverside is included as part of @git.zone/tstest
|
||||
pnpm install --save-dev @git.zone/tstest
|
||||
```
|
||||
|
||||
## Overview
|
||||
|
||||
`@git.zone/tstest/tapbundle_serverside` provides server-side testing utilities exclusively for Node.js runtime. These tools enable shell command execution, environment variable management, HTTPS certificate generation, database testing, object storage testing, and test asset management - all functionality that only makes sense on the server-side.
|
||||
|
||||
## Key Features
|
||||
|
||||
- 🔐 **Environment Variables** - On-demand environment variable loading with qenv
|
||||
- 💻 **Shell Commands** - Execute bash commands during tests
|
||||
- 🔒 **HTTPS Certificates** - Generate self-signed certificates for testing
|
||||
- 🗄️ **MongoDB Testing** - Create ephemeral MongoDB instances
|
||||
- 📦 **S3 Storage Testing** - Create local S3-compatible storage for tests
|
||||
- 📁 **Test File Management** - Download and manage test assets
|
||||
|
||||
## Basic Usage
|
||||
|
||||
```typescript
|
||||
import { tapNodeTools } from '@git.zone/tstest/tapbundle_serverside';
|
||||
import { tap } from '@git.zone/tstest/tapbundle';
|
||||
|
||||
tap.test('should use server-side tools', async () => {
|
||||
// Execute shell commands on the server-side
|
||||
const result = await tapNodeTools.runCommand('echo "hello"');
|
||||
console.log(result);
|
||||
});
|
||||
|
||||
export default tap.start();
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### tapNodeTools
|
||||
|
||||
The main singleton instance providing all Node.js-specific utilities.
|
||||
|
||||
#### Environment Variables
|
||||
|
||||
##### `getQenv()`
|
||||
|
||||
Get the qenv instance for managing environment variables from `.nogit/` directory.
|
||||
|
||||
```typescript
|
||||
const qenv = await tapNodeTools.getQenv();
|
||||
// qenv will load from .env files in .nogit/ directory
|
||||
```
|
||||
|
||||
##### `getEnvVarOnDemand(envVarName)`
|
||||
|
||||
Request an environment variable. If not available, qenv will prompt for it and store it securely.
|
||||
|
||||
```typescript
|
||||
tap.test('should get API key', async () => {
|
||||
const apiKey = await tapNodeTools.getEnvVarOnDemand('GITHUB_API_KEY');
|
||||
// If GITHUB_API_KEY is not set, qenv will prompt for it
|
||||
// The value is stored in .nogit/.env for future use
|
||||
});
|
||||
```
|
||||
|
||||
**Use Cases:**
|
||||
- API keys for integration tests
|
||||
- Database credentials
|
||||
- Service endpoints
|
||||
- Any sensitive configuration needed for testing
|
||||
|
||||
#### Shell Commands
|
||||
|
||||
##### `runCommand(command)`
|
||||
|
||||
Execute a bash command and return the result.
|
||||
|
||||
```typescript
|
||||
tap.test('should execute shell commands', async () => {
|
||||
const result = await tapNodeTools.runCommand('ls -la');
|
||||
console.log(result.stdout);
|
||||
});
|
||||
```
|
||||
|
||||
**Use Cases:**
|
||||
- Setup test environment
|
||||
- Execute CLI tools
|
||||
- File system operations
|
||||
- Process management
|
||||
|
||||
#### HTTPS Certificates
|
||||
|
||||
##### `createHttpsCert(commonName?, allowSelfSigned?)`
|
||||
|
||||
Generate a self-signed HTTPS certificate for testing secure connections.
|
||||
|
||||
```typescript
|
||||
tap.test('should create HTTPS server', async () => {
|
||||
const { key, cert } = await tapNodeTools.createHttpsCert('localhost', true);
|
||||
|
||||
// Use with Node.js https module
|
||||
const server = https.createServer({ key, cert }, (req, res) => {
|
||||
res.end('Hello Secure World');
|
||||
});
|
||||
|
||||
server.listen(3000);
|
||||
});
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `commonName` (optional): Certificate common name, default: 'localhost'
|
||||
- `allowSelfSigned` (optional): Allow self-signed certificates by setting `NODE_TLS_REJECT_UNAUTHORIZED=0`, default: true
|
||||
|
||||
**Returns:**
|
||||
- `key`: PEM-encoded private key
|
||||
- `cert`: PEM-encoded certificate
|
||||
|
||||
**Use Cases:**
|
||||
- Testing HTTPS servers
|
||||
- Testing secure WebSocket connections
|
||||
- Testing certificate validation logic
|
||||
- Mocking secure external services
|
||||
|
||||
#### Database Testing
|
||||
|
||||
##### `createSmartmongo()`
|
||||
|
||||
Create an ephemeral MongoDB instance for testing. Automatically started and ready to use.
|
||||
|
||||
```typescript
|
||||
import { tapNodeTools } from '@git.zone/tstest/tapbundle_serverside';
|
||||
|
||||
tap.test('should use MongoDB', async () => {
|
||||
const mongoInstance = await tapNodeTools.createSmartmongo();
|
||||
|
||||
// Use the MongoDB instance
|
||||
const db = await mongoInstance.getDatabase('testdb');
|
||||
const collection = await db.getCollection('users');
|
||||
|
||||
await collection.insertOne({ name: 'Alice', age: 30 });
|
||||
const user = await collection.findOne({ name: 'Alice' });
|
||||
|
||||
expect(user.age).toEqual(30);
|
||||
|
||||
// Cleanup (optional - instance will be cleaned up automatically)
|
||||
await mongoInstance.stop();
|
||||
});
|
||||
|
||||
export default tap.start();
|
||||
```
|
||||
|
||||
**Features:**
|
||||
- Ephemeral instance (starts fresh)
|
||||
- Automatic cleanup
|
||||
- Full MongoDB API via [@push.rocks/smartmongo](https://code.foss.global/push.rocks/smartmongo)
|
||||
|
||||
**Use Cases:**
|
||||
- Testing database operations
|
||||
- Integration tests with MongoDB
|
||||
- Testing data models
|
||||
- Schema validation tests
|
||||
|
||||
#### Storage Testing
|
||||
|
||||
##### `createSmarts3()`
|
||||
|
||||
Create a local S3-compatible storage instance for testing object storage operations.
|
||||
|
||||
```typescript
|
||||
import { tapNodeTools } from '@git.zone/tstest/tapbundle_serverside';
|
||||
|
||||
tap.test('should use S3 storage', async () => {
|
||||
const s3Instance = await tapNodeTools.createSmarts3();
|
||||
|
||||
// Use the S3 instance (MinIO-compatible API)
|
||||
const bucket = await s3Instance.createBucket('test-bucket');
|
||||
await bucket.putObject('file.txt', Buffer.from('Hello S3'));
|
||||
const file = await bucket.getObject('file.txt');
|
||||
|
||||
expect(file.toString()).toEqual('Hello S3');
|
||||
|
||||
// Cleanup
|
||||
await s3Instance.stop();
|
||||
});
|
||||
|
||||
export default tap.start();
|
||||
```
|
||||
|
||||
**Configuration:**
|
||||
- Port: 3003 (default)
|
||||
- Clean slate: true (starts fresh each time)
|
||||
- Full S3-compatible API via [@push.rocks/smarts3](https://code.foss.global/push.rocks/smarts3)
|
||||
|
||||
**Use Cases:**
|
||||
- Testing file uploads/downloads
|
||||
- Testing object storage operations
|
||||
- Testing backup/restore logic
|
||||
- Mocking cloud storage
|
||||
|
||||
### TestFileProvider
|
||||
|
||||
Utility for downloading and managing test assets.
|
||||
|
||||
#### `getDockerAlpineImageAsLocalTarball()`
|
||||
|
||||
Download the Alpine Linux Docker image as a tarball for testing.
|
||||
|
||||
```typescript
|
||||
import { tapNodeTools } from '@git.zone/tstest/tapbundle_serverside';
|
||||
|
||||
tap.test('should provide docker image', async () => {
|
||||
const tarballPath = await tapNodeTools.testFileProvider.getDockerAlpineImageAsLocalTarball();
|
||||
|
||||
// Use the tarball path
|
||||
// Path: ./.nogit/testfiles/alpine.tar
|
||||
|
||||
expect(tarballPath).toMatch(/alpine\.tar$/);
|
||||
});
|
||||
|
||||
export default tap.start();
|
||||
```
|
||||
|
||||
**Features:**
|
||||
- Downloads from https://code.foss.global/testassets/docker
|
||||
- Caches in `.nogit/testfiles/` directory
|
||||
- Returns local file path
|
||||
|
||||
**Use Cases:**
|
||||
- Testing Docker operations
|
||||
- Testing container deployment
|
||||
- Testing image handling logic
|
||||
|
||||
### Path Utilities
|
||||
|
||||
The module exports useful path constants:
|
||||
|
||||
```typescript
|
||||
import * as paths from '@git.zone/tstest/tapbundle_serverside/paths';
|
||||
|
||||
console.log(paths.cwd); // Current working directory
|
||||
console.log(paths.testFilesDir); // ./.nogit/testfiles/
|
||||
```
|
||||
|
||||
## Patterns and Best Practices
|
||||
|
||||
### Testing with External Services
|
||||
|
||||
```typescript
|
||||
import { tapNodeTools } from '@git.zone/tstest/tapbundle_serverside';
|
||||
import { tap, expect } from '@git.zone/tstest/tapbundle';
|
||||
|
||||
tap.describe('User Service Integration', () => {
|
||||
let mongoInstance;
|
||||
let db;
|
||||
|
||||
tap.beforeEach(async () => {
|
||||
mongoInstance = await tapNodeTools.createSmartmongo();
|
||||
db = await mongoInstance.getDatabase('testdb');
|
||||
});
|
||||
|
||||
tap.test('should create user', async () => {
|
||||
const users = await db.getCollection('users');
|
||||
await users.insertOne({ name: 'Bob', email: 'bob@example.com' });
|
||||
|
||||
const user = await users.findOne({ name: 'Bob' });
|
||||
expect(user.email).toEqual('bob@example.com');
|
||||
});
|
||||
|
||||
tap.afterEach(async () => {
|
||||
await mongoInstance.stop();
|
||||
});
|
||||
});
|
||||
|
||||
export default tap.start();
|
||||
```
|
||||
|
||||
### Testing HTTPS Servers
|
||||
|
||||
```typescript
|
||||
import { tapNodeTools } from '@git.zone/tstest/tapbundle_serverside';
|
||||
import { tap, expect } from '@git.zone/tstest/tapbundle';
|
||||
import * as https from 'https';
|
||||
|
||||
tap.test('should serve over HTTPS', async () => {
|
||||
const { key, cert } = await tapNodeTools.createHttpsCert();
|
||||
|
||||
const server = https.createServer({ key, cert }, (req, res) => {
|
||||
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
||||
res.end('Secure Response');
|
||||
});
|
||||
|
||||
await new Promise((resolve) => {
|
||||
server.listen(8443, () => resolve(undefined));
|
||||
});
|
||||
|
||||
// Test the server
|
||||
const response = await fetch('https://localhost:8443');
|
||||
const text = await response.text();
|
||||
expect(text).toEqual('Secure Response');
|
||||
|
||||
// Cleanup
|
||||
server.close();
|
||||
});
|
||||
|
||||
export default tap.start();
|
||||
```
|
||||
|
||||
### Environment-Dependent Tests
|
||||
|
||||
```typescript
|
||||
import { tapNodeTools } from '@git.zone/tstest/tapbundle_serverside';
|
||||
import { tap, expect } from '@git.zone/tstest/tapbundle';
|
||||
|
||||
tap.test('should authenticate with GitHub', async () => {
|
||||
const githubToken = await tapNodeTools.getEnvVarOnDemand('GITHUB_TOKEN');
|
||||
|
||||
// Use the token for API calls
|
||||
const response = await fetch('https://api.github.com/user', {
|
||||
headers: {
|
||||
Authorization: `Bearer ${githubToken}`
|
||||
}
|
||||
});
|
||||
|
||||
expect(response.ok).toBeTruthy();
|
||||
});
|
||||
|
||||
export default tap.start();
|
||||
```
|
||||
|
||||
## Runtime Requirements
|
||||
|
||||
⚠️ **Server-Side Only (Node.js)**: All utilities in this module are designed exclusively for server-side testing in Node.js runtime. They provide functionality like shell command execution, file system operations, and process management that only make sense on the server.
|
||||
|
||||
**NOT available in:**
|
||||
- Browser environments
|
||||
- Deno runtime
|
||||
- Bun runtime
|
||||
|
||||
**Important:** Import tapbundle_serverside only in tests that run exclusively on the server-side (`.node.ts` test files). For cross-runtime tests, these utilities will fail in non-Node environments.
|
||||
|
||||
## File Naming
|
||||
|
||||
Use Node.js-specific file naming when using these utilities:
|
||||
|
||||
```
|
||||
test/mytest.node.ts ✅ Node.js only
|
||||
test/mytest.node+deno.ts ❌ Will fail in Deno
|
||||
test/mytest.browser+node.ts ⚠️ Browser won't have access to these tools
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
|
||||
This module uses the following packages:
|
||||
- [@push.rocks/qenv](https://code.foss.global/push.rocks/qenv) - Environment variable management
|
||||
- [@push.rocks/smartshell](https://code.foss.global/push.rocks/smartshell) - Shell command execution
|
||||
- [@push.rocks/smartcrypto](https://code.foss.global/push.rocks/smartcrypto) - Certificate generation
|
||||
- [@push.rocks/smartmongo](https://code.foss.global/push.rocks/smartmongo) - MongoDB testing
|
||||
- [@push.rocks/smarts3](https://code.foss.global/push.rocks/smarts3) - S3 storage testing
|
||||
- [@push.rocks/smartfile](https://code.foss.global/push.rocks/smartfile) - File operations
|
||||
- [@push.rocks/smartrequest](https://code.foss.global/push.rocks/smartrequest) - HTTP requests
|
||||
|
||||
## Legal
|
||||
|
||||
This project is licensed under MIT.
|
||||
|
||||
© 2025 Task Venture Capital GmbH. All rights reserved.
|
||||
3
ts_tapbundle_serverside/tspublish.json
Normal file
3
ts_tapbundle_serverside/tspublish.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"order": 3
|
||||
}
|
||||
Reference in New Issue
Block a user