Initial Version of sitemap.xml spec
This commit is contained in:
256
tests/unit/auth.test.js
Normal file
256
tests/unit/auth.test.js
Normal file
@@ -0,0 +1,256 @@
|
||||
/**
|
||||
* Unit Tests: Service Account Authentication
|
||||
*
|
||||
* Tests T033-T034: Test JWT authentication and credential validation
|
||||
* Tests the auth.js module in isolation
|
||||
*
|
||||
* @module tests/unit/auth
|
||||
*/
|
||||
|
||||
import { describe, it, beforeEach } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
|
||||
// =============================================================================
|
||||
// T033: Unit test for Service Account JWT authentication
|
||||
// =============================================================================
|
||||
|
||||
describe('T033: Service Account JWT Authentication', () => {
|
||||
let originalEnv;
|
||||
|
||||
beforeEach(() => {
|
||||
// Save original env
|
||||
originalEnv = process.env.GOOGLE_SERVICE_ACCOUNT_KEY;
|
||||
});
|
||||
|
||||
it('should create GoogleAuth client from GOOGLE_SERVICE_ACCOUNT_KEY env var', async () => {
|
||||
// Mock credentials as inline JSON (per clarification #1)
|
||||
const mockCredentials = {
|
||||
type: 'service_account',
|
||||
project_id: 'test-project',
|
||||
private_key_id: 'key123',
|
||||
private_key: '-----BEGIN PRIVATE KEY-----\nMOCK_KEY\n-----END PRIVATE KEY-----\n',
|
||||
client_email: 'test@test-project.iam.gserviceaccount.com',
|
||||
client_id: '123456789',
|
||||
auth_uri: 'https://accounts.google.com/o/oauth2/auth',
|
||||
token_uri: 'https://oauth2.googleapis.com/token',
|
||||
auth_provider_x509_cert_url: 'https://www.googleapis.com/oauth2/v1/certs'
|
||||
};
|
||||
|
||||
// Set env var with inline JSON
|
||||
process.env.GOOGLE_SERVICE_ACCOUNT_KEY = JSON.stringify(mockCredentials);
|
||||
|
||||
// TODO: Import and call initializeAuth from src/auth.js
|
||||
// const { initializeAuth } = await import('../../src/auth.js');
|
||||
// const auth = await initializeAuth();
|
||||
|
||||
// Verify GoogleAuth was created with correct credentials
|
||||
// assert.ok(auth, 'Should return auth client');
|
||||
// assert.equal(auth.credentials.client_email, mockCredentials.client_email, 'Should use client_email from env var');
|
||||
|
||||
// Restore env
|
||||
if (originalEnv) {
|
||||
process.env.GOOGLE_SERVICE_ACCOUNT_KEY = originalEnv;
|
||||
} else {
|
||||
delete process.env.GOOGLE_SERVICE_ACCOUNT_KEY;
|
||||
}
|
||||
});
|
||||
|
||||
it('should use correct Drive API scope (read-only)', async () => {
|
||||
const mockCredentials = {
|
||||
type: 'service_account',
|
||||
project_id: 'test-project',
|
||||
private_key: '-----BEGIN PRIVATE KEY-----\nMOCK_KEY\n-----END PRIVATE KEY-----\n',
|
||||
client_email: 'test@test-project.iam.gserviceaccount.com'
|
||||
};
|
||||
|
||||
process.env.GOOGLE_SERVICE_ACCOUNT_KEY = JSON.stringify(mockCredentials);
|
||||
|
||||
// TODO: Import and call initializeAuth
|
||||
// const { initializeAuth } = await import('../../src/auth.js');
|
||||
// const auth = await initializeAuth();
|
||||
|
||||
// Verify scope is read-only
|
||||
const expectedScope = 'https://www.googleapis.com/auth/drive.readonly';
|
||||
// assert.ok(auth.scopes.includes(expectedScope), 'Should use drive.readonly scope');
|
||||
|
||||
// Restore env
|
||||
if (originalEnv) {
|
||||
process.env.GOOGLE_SERVICE_ACCOUNT_KEY = originalEnv;
|
||||
} else {
|
||||
delete process.env.GOOGLE_SERVICE_ACCOUNT_KEY;
|
||||
}
|
||||
});
|
||||
|
||||
it('should parse inline JSON from env var correctly', async () => {
|
||||
// Test with different JSON formatting (whitespace, escaped quotes)
|
||||
const mockCredentials = {
|
||||
client_email: 'test@project.iam.gserviceaccount.com',
|
||||
private_key: '-----BEGIN PRIVATE KEY-----\nMOCK_KEY\n-----END PRIVATE KEY-----\n',
|
||||
project_id: 'test-project'
|
||||
};
|
||||
|
||||
// Set with extra whitespace
|
||||
process.env.GOOGLE_SERVICE_ACCOUNT_KEY = JSON.stringify(mockCredentials, null, 2);
|
||||
|
||||
// TODO: Import and call initializeAuth
|
||||
// const { initializeAuth } = await import('../../src/auth.js');
|
||||
// const auth = await initializeAuth();
|
||||
|
||||
// Should parse correctly despite formatting
|
||||
// assert.ok(auth, 'Should parse JSON with whitespace');
|
||||
|
||||
// Restore env
|
||||
if (originalEnv) {
|
||||
process.env.GOOGLE_SERVICE_ACCOUNT_KEY = originalEnv;
|
||||
} else {
|
||||
delete process.env.GOOGLE_SERVICE_ACCOUNT_KEY;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// =============================================================================
|
||||
// T034: Unit test for credential validation
|
||||
// =============================================================================
|
||||
|
||||
describe('T034: Credential Validation', () => {
|
||||
it('should detect missing client_email field', async () => {
|
||||
const invalidCredentials = {
|
||||
private_key: '-----BEGIN PRIVATE KEY-----\nMOCK_KEY\n-----END PRIVATE KEY-----\n',
|
||||
project_id: 'test-project'
|
||||
// Missing client_email
|
||||
};
|
||||
|
||||
process.env.GOOGLE_SERVICE_ACCOUNT_KEY = JSON.stringify(invalidCredentials);
|
||||
|
||||
// TODO: Import validateCredentials from src/auth.js
|
||||
// const { validateCredentials } = await import('../../src/auth.js');
|
||||
|
||||
// Should throw error for missing client_email
|
||||
// await assert.rejects(
|
||||
// async () => await validateCredentials(invalidCredentials),
|
||||
// { message: /client_email/ },
|
||||
// 'Should reject credentials without client_email'
|
||||
// );
|
||||
|
||||
delete process.env.GOOGLE_SERVICE_ACCOUNT_KEY;
|
||||
});
|
||||
|
||||
it('should detect missing private_key field', async () => {
|
||||
const invalidCredentials = {
|
||||
client_email: 'test@project.iam.gserviceaccount.com',
|
||||
project_id: 'test-project'
|
||||
// Missing private_key
|
||||
};
|
||||
|
||||
process.env.GOOGLE_SERVICE_ACCOUNT_KEY = JSON.stringify(invalidCredentials);
|
||||
|
||||
// TODO: Import validateCredentials
|
||||
// const { validateCredentials } = await import('../../src/auth.js');
|
||||
|
||||
// Should throw error for missing private_key
|
||||
// await assert.rejects(
|
||||
// async () => await validateCredentials(invalidCredentials),
|
||||
// { message: /private_key/ },
|
||||
// 'Should reject credentials without private_key'
|
||||
// );
|
||||
|
||||
delete process.env.GOOGLE_SERVICE_ACCOUNT_KEY;
|
||||
});
|
||||
|
||||
it('should detect missing project_id field', async () => {
|
||||
const invalidCredentials = {
|
||||
client_email: 'test@project.iam.gserviceaccount.com',
|
||||
private_key: '-----BEGIN PRIVATE KEY-----\nMOCK_KEY\n-----END PRIVATE KEY-----\n'
|
||||
// Missing project_id
|
||||
};
|
||||
|
||||
process.env.GOOGLE_SERVICE_ACCOUNT_KEY = JSON.stringify(invalidCredentials);
|
||||
|
||||
// TODO: Import validateCredentials
|
||||
// const { validateCredentials } = await import('../../src/auth.js');
|
||||
|
||||
// Should throw error for missing project_id
|
||||
// await assert.rejects(
|
||||
// async () => await validateCredentials(invalidCredentials),
|
||||
// { message: /project_id/ },
|
||||
// 'Should reject credentials without project_id'
|
||||
// );
|
||||
|
||||
delete process.env.GOOGLE_SERVICE_ACCOUNT_KEY;
|
||||
});
|
||||
|
||||
it('should detect empty credential fields', async () => {
|
||||
const invalidCredentials = {
|
||||
client_email: '', // Empty
|
||||
private_key: '-----BEGIN PRIVATE KEY-----\nMOCK_KEY\n-----END PRIVATE KEY-----\n',
|
||||
project_id: 'test-project'
|
||||
};
|
||||
|
||||
process.env.GOOGLE_SERVICE_ACCOUNT_KEY = JSON.stringify(invalidCredentials);
|
||||
|
||||
// TODO: Import validateCredentials
|
||||
// const { validateCredentials } = await import('../../src/auth.js');
|
||||
|
||||
// Should throw error for empty client_email
|
||||
// await assert.rejects(
|
||||
// async () => await validateCredentials(invalidCredentials),
|
||||
// { message: /client_email.*empty/ },
|
||||
// 'Should reject empty client_email'
|
||||
// );
|
||||
|
||||
delete process.env.GOOGLE_SERVICE_ACCOUNT_KEY;
|
||||
});
|
||||
|
||||
it('should accept valid credentials', async () => {
|
||||
const validCredentials = {
|
||||
type: 'service_account',
|
||||
project_id: 'test-project',
|
||||
private_key: '-----BEGIN PRIVATE KEY-----\nMOCK_KEY\n-----END PRIVATE KEY-----\n',
|
||||
client_email: 'test@test-project.iam.gserviceaccount.com'
|
||||
};
|
||||
|
||||
process.env.GOOGLE_SERVICE_ACCOUNT_KEY = JSON.stringify(validCredentials);
|
||||
|
||||
// TODO: Import validateCredentials
|
||||
// const { validateCredentials } = await import('../../src/auth.js');
|
||||
|
||||
// Should not throw for valid credentials
|
||||
// await assert.doesNotReject(
|
||||
// async () => await validateCredentials(validCredentials),
|
||||
// 'Should accept valid credentials'
|
||||
// );
|
||||
|
||||
delete process.env.GOOGLE_SERVICE_ACCOUNT_KEY;
|
||||
});
|
||||
|
||||
it('should trigger fatal error handler on invalid credentials (exit code 1)', async () => {
|
||||
// Per T016: Fatal error handler should log to stderr and exit with code 1
|
||||
const invalidCredentials = {
|
||||
invalid: 'structure'
|
||||
};
|
||||
|
||||
process.env.GOOGLE_SERVICE_ACCOUNT_KEY = JSON.stringify(invalidCredentials);
|
||||
|
||||
// TODO: Import initializeAuth which should call fatal error handler
|
||||
// const { initializeAuth } = await import('../../src/auth.js');
|
||||
|
||||
// Mock process.exit to prevent actual exit
|
||||
// let exitCode;
|
||||
// const originalExit = process.exit;
|
||||
// process.exit = (code) => { exitCode = code; throw new Error('EXIT'); };
|
||||
|
||||
// try {
|
||||
// await initializeAuth();
|
||||
// } catch (e) {
|
||||
// if (e.message === 'EXIT') {
|
||||
// assert.equal(exitCode, 1, 'Should exit with code 1 on invalid credentials');
|
||||
// } else {
|
||||
// throw e;
|
||||
// }
|
||||
// } finally {
|
||||
// process.exit = originalExit;
|
||||
// }
|
||||
|
||||
delete process.env.GOOGLE_SERVICE_ACCOUNT_KEY;
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user