winx_prinx-api / server /scratch /test_token_refresh.js
Sasha
Optimize moderation logging: fix duplicate collisions, auto-refresh streamer OAuth tokens, and implement IRC keep-alive timeouts. Add unit tests.
e0e1da7
Raw
History Blame
5.97 kB
// Setup testing database environment variables BEFORE any imports
process.env.DB_MODE = 'sqlite';
process.env.SQLITE_DB_PATH = './test_database.db';
// Clear Supabase keys to force SQLite mode
process.env.SUPABASE_URL = '';
process.env.SUPABASE_KEY = '';
process.env.SUPABASE_SERVICE_ROLE_KEY = '';
// Mock environment variables for Twitch client
process.env.TWITCH_CLIENT_ID = 'mocked_client_id';
process.env.TWITCH_CLIENT_SECRET = 'mocked_client_secret';
import Database from 'better-sqlite3';
import fs from 'fs';
import axios from 'axios';
// Clean up test database
if (fs.existsSync('./test_database.db')) {
fs.unlinkSync('./test_database.db');
}
const sqliteDb = new Database('./test_database.db');
// Create settings table
sqliteDb.exec(`
CREATE TABLE IF NOT EXISTS settings (
key TEXT PRIMARY KEY,
value TEXT NOT NULL
);
`);
// Insert initial expired token and refresh token
sqliteDb.prepare(`
INSERT INTO settings (key, value)
VALUES ('twitch_streamer_access_token', 'expired_token_value')
`).run();
sqliteDb.prepare(`
INSERT INTO settings (key, value)
VALUES ('twitch_streamer_refresh_token', 'valid_refresh_token_value')
`).run();
// Mock Axios methods
let validateCalls = 0;
let refreshCalls = 0;
let refreshParamsReceived = null;
axios.get = async (url, config) => {
if (url === 'https://id.twitch.tv/oauth2/validate') {
validateCalls++;
const authHeader = config?.headers?.Authorization;
if (authHeader === 'Bearer valid_mocked_token') {
// Mock success for valid token
return { data: { client_id: 'mocked_client_id' } };
} else {
// Mock expiration/invalid token error
const err = new Error('Unauthorized');
err.response = { status: 401, data: { message: 'invalid oauth token' } };
throw err;
}
}
throw new Error(`Unexpected GET request to ${url}`);
};
axios.post = async (url, data, config) => {
if (url === 'https://id.twitch.tv/oauth2/token') {
refreshCalls++;
refreshParamsReceived = config?.params;
return {
data: {
access_token: 'new_refreshed_access_token',
refresh_token: 'new_refreshed_refresh_token'
}
};
}
throw new Error(`Unexpected POST request to ${url}`);
};
// Dynamically import db.js and eventsub.js so they read correct environment variables and use the mocked axios
const { getSetting } = await import('../db.js');
const { getOrRefreshAccessToken } = await import('../eventsub.js');
async function runTest() {
console.log('--- STARTING TOKEN REFRESH TEST ---');
// Scenario 1: Initial call with expired token. Should fail validate, call refresh, and return new token.
console.log('Scenario 1: Testing token validation failure and refresh flow...');
const token = await getOrRefreshAccessToken();
console.log('Returned token:', token);
console.log('Validate calls:', validateCalls);
console.log('Refresh calls:', refreshCalls);
console.log('Params received on refresh:', refreshParamsReceived);
// Assertions
if (token !== 'new_refreshed_access_token') {
console.error('FAIL: Expected new refreshed access token, got:', token);
process.exit(1);
}
if (validateCalls !== 1) {
console.error('FAIL: Expected 1 validate call, got:', validateCalls);
process.exit(1);
}
if (refreshCalls !== 1) {
console.error('FAIL: Expected 1 refresh call, got:', refreshCalls);
process.exit(1);
}
if (!refreshParamsReceived || refreshParamsReceived.refresh_token !== 'valid_refresh_token_value') {
console.error('FAIL: Incorrect refresh token sent in params:', refreshParamsReceived);
process.exit(1);
}
// Verify DB updated settings
const dbAccessToken = sqliteDb.prepare("SELECT value FROM settings WHERE key = 'twitch_streamer_access_token'").get()?.value;
const dbRefreshToken = sqliteDb.prepare("SELECT value FROM settings WHERE key = 'twitch_streamer_refresh_token'").get()?.value;
console.log('DB Access Token:', dbAccessToken);
console.log('DB Refresh Token:', dbRefreshToken);
if (dbAccessToken !== 'new_refreshed_access_token' || dbRefreshToken !== 'new_refreshed_refresh_token') {
console.error('FAIL: Settings not updated in database correctly');
process.exit(1);
}
// Scenario 2: Subsequent call with the now valid token. Should validate successfully and not call refresh.
console.log('Scenario 2: Testing valid token bypasses refresh...');
// Update mock token validation check to succeed for this new token
axios.get = async (url, config) => {
if (url === 'https://id.twitch.tv/oauth2/validate') {
validateCalls++;
const authHeader = config?.headers?.Authorization;
if (authHeader === 'Bearer new_refreshed_access_token') {
return { data: { client_id: 'mocked_client_id' } };
}
const err = new Error('Unauthorized');
err.response = { status: 401 };
throw err;
}
throw new Error(`Unexpected GET request to ${url}`);
};
const tokenScenario2 = await getOrRefreshAccessToken();
console.log('Scenario 2 Returned token:', tokenScenario2);
console.log('Scenario 2 Validate calls total:', validateCalls);
console.log('Scenario 2 Refresh calls total:', refreshCalls);
if (tokenScenario2 !== 'new_refreshed_access_token') {
console.error('FAIL: Expected token to remain new_refreshed_access_token, got:', tokenScenario2);
process.exit(1);
}
if (validateCalls !== 2) {
console.error('FAIL: Expected validate calls to increment to 2, got:', validateCalls);
process.exit(1);
}
if (refreshCalls !== 1) {
console.error('FAIL: Expected refresh calls to remain 1, got:', refreshCalls);
process.exit(1);
}
console.log('SUCCESS: Token refresh flow successfully verified and tested!');
// Clean up
sqliteDb.close();
if (fs.existsSync('./test_database.db')) {
fs.unlinkSync('./test_database.db');
}
}
runTest().catch(err => {
console.error('Test crashed:', err);
process.exit(1);
});