Spaces:
Sleeping
Sleeping
Sasha
Optimize moderation logging: fix duplicate collisions, auto-refresh streamer OAuth tokens, and implement IRC keep-alive timeouts. Add unit tests.
e0e1da7 | // 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); | |
| }); | |