bulltrackers-module 1.0.765 ā 1.0.768
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/functions/computation-system-v2/computations/BehavioralAnomaly.js +298 -186
- package/functions/computation-system-v2/computations/NewSectorExposure.js +82 -35
- package/functions/computation-system-v2/computations/NewSocialPost.js +52 -24
- package/functions/computation-system-v2/computations/PopularInvestorProfileMetrics.js +354 -641
- package/functions/computation-system-v2/config/bulltrackers.config.js +26 -14
- package/functions/computation-system-v2/framework/core/Manifest.js +9 -16
- package/functions/computation-system-v2/framework/core/RunAnalyzer.js +2 -1
- package/functions/computation-system-v2/framework/data/DataFetcher.js +142 -4
- package/functions/computation-system-v2/framework/execution/Orchestrator.js +119 -122
- package/functions/computation-system-v2/framework/storage/StorageManager.js +16 -18
- package/functions/computation-system-v2/framework/testing/ComputationTester.js +155 -66
- package/functions/computation-system-v2/handlers/scheduler.js +15 -5
- package/functions/computation-system-v2/scripts/test-computation-dag.js +109 -0
- package/functions/task-engine/helpers/data_storage_helpers.js +6 -6
- package/package.json +1 -1
- package/functions/computation-system-v2/computations/PopularInvestorRiskAssessment.js +0 -176
- package/functions/computation-system-v2/computations/PopularInvestorRiskMetrics.js +0 -294
- package/functions/computation-system-v2/computations/UserPortfolioSummary.js +0 -172
- package/functions/computation-system-v2/scripts/migrate-sectors.js +0 -73
- package/functions/computation-system-v2/test/analyze-results.js +0 -238
- package/functions/computation-system-v2/test/other/test-dependency-cascade.js +0 -150
- package/functions/computation-system-v2/test/other/test-dispatcher.js +0 -317
- package/functions/computation-system-v2/test/other/test-framework.js +0 -500
- package/functions/computation-system-v2/test/other/test-real-execution.js +0 -166
- package/functions/computation-system-v2/test/other/test-real-integration.js +0 -194
- package/functions/computation-system-v2/test/other/test-refactor-e2e.js +0 -131
- package/functions/computation-system-v2/test/other/test-results.json +0 -31
- package/functions/computation-system-v2/test/other/test-risk-metrics-computation.js +0 -329
- package/functions/computation-system-v2/test/other/test-scheduler.js +0 -204
- package/functions/computation-system-v2/test/other/test-storage.js +0 -449
- package/functions/computation-system-v2/test/run-pipeline-test.js +0 -554
- package/functions/computation-system-v2/test/test-full-pipeline.js +0 -227
- package/functions/computation-system-v2/test/test-worker-pool.js +0 -266
|
@@ -1,500 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview Framework Test Script
|
|
3
|
-
*
|
|
4
|
-
* Run with: node test/test-framework.js
|
|
5
|
-
*
|
|
6
|
-
* This tests the v2 framework independently before integrating with the workflow.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
const path = require('path');
|
|
10
|
-
|
|
11
|
-
// Set up environment (would normally come from Cloud Functions)
|
|
12
|
-
process.env.GCP_PROJECT_ID = process.env.GCP_PROJECT_ID || 'stocks-12345';
|
|
13
|
-
process.env.BIGQUERY_DATASET_ID = process.env.BIGQUERY_DATASET_ID || 'bulltrackers_data';
|
|
14
|
-
|
|
15
|
-
// Simple logger
|
|
16
|
-
const logger = {
|
|
17
|
-
log: (level, message) => {
|
|
18
|
-
const timestamp = new Date().toISOString().slice(11, 19);
|
|
19
|
-
const levelPad = level.padEnd(5);
|
|
20
|
-
console.log(`[${timestamp}] ${levelPad} ${message}`);
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
// ============================================================================
|
|
25
|
-
// TEST 1: Manifest Building with Dependencies
|
|
26
|
-
// ============================================================================
|
|
27
|
-
async function testManifestBuilding() {
|
|
28
|
-
console.log('\n=== TEST: Manifest Building with Dependencies ===\n');
|
|
29
|
-
|
|
30
|
-
const { ManifestBuilder } = require('../../framework/core/Manifest');
|
|
31
|
-
const UserPortfolioSummary = require('../../computations/UserPortfolioSummary');
|
|
32
|
-
const PopularInvestorProfileMetrics = require('../../computations/PopularInvestorProfileMetrics');
|
|
33
|
-
const PopularInvestorRiskAssessment = require('../../computations/PopularInvestorRiskAssessment');
|
|
34
|
-
|
|
35
|
-
const config = { epoch: 'test-v1' };
|
|
36
|
-
const builder = new ManifestBuilder(config, logger);
|
|
37
|
-
|
|
38
|
-
// Test with all 3 computations, including the dependent one
|
|
39
|
-
const manifest = builder.build([
|
|
40
|
-
UserPortfolioSummary,
|
|
41
|
-
PopularInvestorProfileMetrics,
|
|
42
|
-
PopularInvestorRiskAssessment // This depends on PopularInvestorProfileMetrics
|
|
43
|
-
]);
|
|
44
|
-
|
|
45
|
-
console.log('Manifest entries:', manifest.length);
|
|
46
|
-
|
|
47
|
-
// Group by pass and verify
|
|
48
|
-
const passes = builder.groupByPass(manifest);
|
|
49
|
-
const passNumbers = Object.keys(passes).map(Number).sort((a, b) => a - b);
|
|
50
|
-
|
|
51
|
-
console.log(`\nPasses found: ${passNumbers.join(', ')}`);
|
|
52
|
-
|
|
53
|
-
for (const passNum of passNumbers) {
|
|
54
|
-
console.log(`\n Pass ${passNum}:`);
|
|
55
|
-
for (const entry of passes[passNum]) {
|
|
56
|
-
console.log(` š ${entry.originalName || entry.name}`);
|
|
57
|
-
console.log(` Dependencies: ${entry.dependencies.length > 0 ? entry.dependencies.join(', ') : 'none'}`);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Verify Pass Assignment
|
|
62
|
-
const piMetrics = manifest.find(e => e.name === 'popularinvestorprofilemetrics');
|
|
63
|
-
const riskAssessment = manifest.find(e => e.name === 'popularinvestorriskassessment');
|
|
64
|
-
|
|
65
|
-
console.log('\n--- Pass Assignment Verification ---');
|
|
66
|
-
console.log(`PopularInvestorProfileMetrics: Pass ${piMetrics?.pass}`);
|
|
67
|
-
console.log(`PopularInvestorRiskAssessment: Pass ${riskAssessment?.pass}`);
|
|
68
|
-
|
|
69
|
-
if (riskAssessment?.pass > piMetrics?.pass) {
|
|
70
|
-
console.log('\nā
Dependency pass assignment CORRECT!');
|
|
71
|
-
console.log(` Dependent computation (${riskAssessment?.pass}) is in a later pass than its dependency (${piMetrics?.pass})`);
|
|
72
|
-
} else {
|
|
73
|
-
console.log('\nā Dependency pass assignment INCORRECT!');
|
|
74
|
-
console.log(' The dependent should be in a LATER pass than its dependency');
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
console.log('\nā
Manifest building works!\n');
|
|
78
|
-
|
|
79
|
-
return manifest;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// ============================================================================
|
|
83
|
-
// TEST 2: Schema Registry
|
|
84
|
-
// ============================================================================
|
|
85
|
-
async function testSchemaRegistry() {
|
|
86
|
-
console.log('\n=== TEST: Schema Registry ===\n');
|
|
87
|
-
|
|
88
|
-
const { SchemaRegistry } = require('../../framework/data/SchemaRegistry');
|
|
89
|
-
|
|
90
|
-
const config = {
|
|
91
|
-
projectId: process.env.GCP_PROJECT_ID,
|
|
92
|
-
dataset: process.env.BIGQUERY_DATASET_ID,
|
|
93
|
-
location: 'europe-west1'
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
const registry = new SchemaRegistry(config, logger);
|
|
97
|
-
|
|
98
|
-
try {
|
|
99
|
-
// List tables
|
|
100
|
-
console.log('Listing tables...');
|
|
101
|
-
const tables = await registry.listTables();
|
|
102
|
-
console.log(`Found ${tables.length} tables:`, tables.slice(0, 5).join(', '), '...');
|
|
103
|
-
|
|
104
|
-
// Get schema for a table
|
|
105
|
-
if (tables.length > 0) {
|
|
106
|
-
const testTable = tables.find(t => t.includes('portfolio')) || tables[0];
|
|
107
|
-
console.log(`\nFetching schema for '${testTable}'...`);
|
|
108
|
-
const schema = await registry.getSchema(testTable);
|
|
109
|
-
console.log(`Columns (${schema.columns.length}):`);
|
|
110
|
-
for (const col of schema.columns.slice(0, 5)) {
|
|
111
|
-
console.log(` - ${col.name}: ${col.type}${col.nullable ? '' : ' (required)'}`);
|
|
112
|
-
}
|
|
113
|
-
if (schema.columns.length > 5) {
|
|
114
|
-
console.log(` ... and ${schema.columns.length - 5} more`);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// Test validation
|
|
118
|
-
console.log('\nValidating columns...');
|
|
119
|
-
try {
|
|
120
|
-
await registry.validateColumns(testTable, ['date', 'nonexistent_column_xyz']);
|
|
121
|
-
console.log('ā Validation should have failed!');
|
|
122
|
-
} catch (e) {
|
|
123
|
-
console.log('ā
Validation correctly caught invalid column');
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
console.log('\nCache stats:', registry.getStats());
|
|
128
|
-
console.log('\nā
Schema registry works!\n');
|
|
129
|
-
|
|
130
|
-
} catch (e) {
|
|
131
|
-
console.log(`\nā ļø Schema registry test failed (expected if not connected to BigQuery): ${e.message}`);
|
|
132
|
-
console.log('This is OK - the framework structure is correct.\n');
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// ============================================================================
|
|
137
|
-
// TEST 3: Query Builder
|
|
138
|
-
// ============================================================================
|
|
139
|
-
async function testQueryBuilder() {
|
|
140
|
-
console.log('\n=== TEST: Query Builder ===\n');
|
|
141
|
-
|
|
142
|
-
const { SchemaRegistry } = require('../../framework/data/SchemaRegistry');
|
|
143
|
-
const { QueryBuilder } = require('../../framework/data/QueryBuilder');
|
|
144
|
-
|
|
145
|
-
const config = {
|
|
146
|
-
projectId: process.env.GCP_PROJECT_ID,
|
|
147
|
-
dataset: process.env.BIGQUERY_DATASET_ID,
|
|
148
|
-
location: 'europe-west1'
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
const registry = new SchemaRegistry(config, logger);
|
|
152
|
-
const builder = new QueryBuilder(config, registry, logger);
|
|
153
|
-
|
|
154
|
-
try {
|
|
155
|
-
// Build a query (requires BigQuery connection for validation)
|
|
156
|
-
const query = await builder.build({
|
|
157
|
-
table: 'portfolio_snapshots',
|
|
158
|
-
select: ['date', 'user_id', 'portfolio_data'],
|
|
159
|
-
where: { user_type: 'POPULAR_INVESTOR' },
|
|
160
|
-
dateField: 'date',
|
|
161
|
-
targetDate: '2026-01-24',
|
|
162
|
-
lookback: 0
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
console.log('Built query:');
|
|
166
|
-
console.log(query.sql);
|
|
167
|
-
console.log('\nParams:', query.params);
|
|
168
|
-
console.log('\nā
Query builder works!\n');
|
|
169
|
-
|
|
170
|
-
} catch (e) {
|
|
171
|
-
console.log(`\nā ļø Query builder test requires BigQuery connection: ${e.message}`);
|
|
172
|
-
console.log('The framework structure is correct.\n');
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// ============================================================================
|
|
177
|
-
// TEST 4: Computation Validation
|
|
178
|
-
// ============================================================================
|
|
179
|
-
async function testComputationValidation() {
|
|
180
|
-
console.log('\n=== TEST: Computation Validation ===\n');
|
|
181
|
-
|
|
182
|
-
const { Computation } = require('../../framework/core/Computation');
|
|
183
|
-
const UserPortfolioSummary = require('../../computations/UserPortfolioSummary');
|
|
184
|
-
const PopularInvestorProfileMetrics = require('../../computations/PopularInvestorProfileMetrics');
|
|
185
|
-
const PopularInvestorRiskAssessment = require('../../computations/PopularInvestorRiskAssessment');
|
|
186
|
-
|
|
187
|
-
// Test UserPortfolioSummary
|
|
188
|
-
console.log('Testing UserPortfolioSummary...');
|
|
189
|
-
const validation1 = UserPortfolioSummary.validateConfig();
|
|
190
|
-
console.log(' Validation:', validation1.valid ? 'ā
Valid' : `ā Invalid: ${validation1.errors.join(', ')}`);
|
|
191
|
-
|
|
192
|
-
// Test PopularInvestorProfileMetrics
|
|
193
|
-
console.log('\nTesting PopularInvestorProfileMetrics...');
|
|
194
|
-
const validation2 = PopularInvestorProfileMetrics.validateConfig();
|
|
195
|
-
console.log(' Validation:', validation2.valid ? 'ā
Valid' : `ā Invalid: ${validation2.errors.join(', ')}`);
|
|
196
|
-
|
|
197
|
-
// Test PopularInvestorRiskAssessment (with dependency)
|
|
198
|
-
console.log('\nTesting PopularInvestorRiskAssessment...');
|
|
199
|
-
const validation3 = PopularInvestorRiskAssessment.validateConfig();
|
|
200
|
-
console.log(' Validation:', validation3.valid ? 'ā
Valid' : `ā Invalid: ${validation3.errors.join(', ')}`);
|
|
201
|
-
|
|
202
|
-
// Show dependency details
|
|
203
|
-
if (validation3.valid) {
|
|
204
|
-
const config = PopularInvestorRiskAssessment.getConfig();
|
|
205
|
-
console.log('\n Config details:');
|
|
206
|
-
console.log(` Name: ${config.name}`);
|
|
207
|
-
console.log(` Dependencies: ${config.dependencies.join(', ')}`);
|
|
208
|
-
console.log(` Tables required (${Object.keys(config.requires).length}):`);
|
|
209
|
-
for (const [table, spec] of Object.entries(config.requires)) {
|
|
210
|
-
const mandatory = spec.mandatory ? '(mandatory)' : '(optional)';
|
|
211
|
-
console.log(` - ${table}: ${mandatory}`);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// Test instantiation
|
|
216
|
-
console.log('\nTesting instantiation...');
|
|
217
|
-
const instance1 = new UserPortfolioSummary();
|
|
218
|
-
const instance2 = new PopularInvestorProfileMetrics();
|
|
219
|
-
const instance3 = new PopularInvestorRiskAssessment();
|
|
220
|
-
console.log('UserPortfolioSummary instance:', typeof instance1.process === 'function' ? 'ā
' : 'ā');
|
|
221
|
-
console.log('PopularInvestorProfileMetrics instance:', typeof instance2.process === 'function' ? 'ā
' : 'ā');
|
|
222
|
-
console.log('PopularInvestorRiskAssessment instance:', typeof instance3.process === 'function' ? 'ā
' : 'ā');
|
|
223
|
-
|
|
224
|
-
console.log('\nā
Computation validation works!\n');
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
// ============================================================================
|
|
228
|
-
// TEST 5: Dry Run Analysis
|
|
229
|
-
// ============================================================================
|
|
230
|
-
async function testDryRun() {
|
|
231
|
-
console.log('\n=== TEST: Dry Run Analysis ===\n');
|
|
232
|
-
|
|
233
|
-
try {
|
|
234
|
-
const v2 = require('../../index');
|
|
235
|
-
|
|
236
|
-
const report = await v2.analyze({
|
|
237
|
-
date: '2026-01-24',
|
|
238
|
-
logger
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
console.log('Analysis report:');
|
|
242
|
-
console.log(` Runnable: ${report.runnable.length}`);
|
|
243
|
-
console.log(` Skipped: ${report.skipped.length}`);
|
|
244
|
-
console.log(` Blocked: ${report.blocked.length}`);
|
|
245
|
-
console.log(` Impossible: ${report.impossible.length}`);
|
|
246
|
-
|
|
247
|
-
if (report.runnable.length > 0) {
|
|
248
|
-
console.log('\nRunnable computations:');
|
|
249
|
-
for (const c of report.runnable) {
|
|
250
|
-
console.log(` - ${c.name} (Pass ${c.pass}) - ${c.reason}`);
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
if (report.blocked.length > 0) {
|
|
255
|
-
console.log('\nBlocked computations (waiting for dependencies):');
|
|
256
|
-
for (const c of report.blocked) {
|
|
257
|
-
console.log(` - ${c.name}: ${c.reason}`);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
if (report.impossible.length > 0) {
|
|
262
|
-
console.log('\nImpossible computations:');
|
|
263
|
-
for (const c of report.impossible) {
|
|
264
|
-
console.log(` - ${c.name}: ${c.reason}`);
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
console.log('\nā
Dry run analysis works!\n');
|
|
269
|
-
|
|
270
|
-
} catch (e) {
|
|
271
|
-
console.log(`\nā ļø Dry run requires BigQuery connection: ${e.message}\n`);
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
// ============================================================================
|
|
276
|
-
// TEST 6: REAL DATA EXECUTION
|
|
277
|
-
// ============================================================================
|
|
278
|
-
async function testRealExecution() {
|
|
279
|
-
console.log('\n=== TEST: REAL DATA EXECUTION ===\n');
|
|
280
|
-
console.log('ā ļø This test will execute computations and write to BigQuery!\n');
|
|
281
|
-
|
|
282
|
-
try {
|
|
283
|
-
const v2 = require('../../index');
|
|
284
|
-
|
|
285
|
-
// Find a date with data
|
|
286
|
-
console.log('Looking for a date with available data...');
|
|
287
|
-
|
|
288
|
-
// Try recent dates
|
|
289
|
-
const today = new Date();
|
|
290
|
-
let targetDate = null;
|
|
291
|
-
|
|
292
|
-
for (let i = 0; i < 7; i++) {
|
|
293
|
-
const checkDate = new Date(today);
|
|
294
|
-
checkDate.setDate(today.getDate() - i);
|
|
295
|
-
const dateStr = checkDate.toISOString().slice(0, 10);
|
|
296
|
-
|
|
297
|
-
const report = await v2.analyze({ date: dateStr, logger });
|
|
298
|
-
|
|
299
|
-
// Look for a date where we can run something
|
|
300
|
-
if (report.runnable.length > 0) {
|
|
301
|
-
targetDate = dateStr;
|
|
302
|
-
console.log(`Found runnable date: ${dateStr}`);
|
|
303
|
-
console.log(` Runnable: ${report.runnable.map(c => c.name).join(', ')}`);
|
|
304
|
-
break;
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
if (!targetDate) {
|
|
309
|
-
console.log('ā ļø No runnable computations found in the last 7 days.');
|
|
310
|
-
console.log(' Make sure root data exists in BigQuery.\n');
|
|
311
|
-
return;
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
// Execute with dryRun first to see what would happen
|
|
315
|
-
console.log(`\n--- Dry Run for ${targetDate} ---`);
|
|
316
|
-
const dryResult = await v2.execute({
|
|
317
|
-
date: targetDate,
|
|
318
|
-
dryRun: true,
|
|
319
|
-
logger
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
console.log('\nDry run results:');
|
|
323
|
-
console.log(` Completed: ${dryResult.summary.completed}`);
|
|
324
|
-
console.log(` Skipped: ${dryResult.summary.skipped}`);
|
|
325
|
-
console.log(` Blocked: ${dryResult.summary.blocked}`);
|
|
326
|
-
console.log(` Impossible: ${dryResult.summary.impossible}`);
|
|
327
|
-
console.log(` Errors: ${dryResult.summary.errors}`);
|
|
328
|
-
|
|
329
|
-
if (dryResult.completed.length > 0) {
|
|
330
|
-
console.log('\nCompleted computations:');
|
|
331
|
-
for (const c of dryResult.completed) {
|
|
332
|
-
console.log(` - ${c.name}: ${c.resultCount} results in ${c.duration}ms`);
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
// Now execute for real (comment out to skip writing)
|
|
337
|
-
console.log(`\n--- REAL Execution for ${targetDate} ---`);
|
|
338
|
-
console.log('Writing results to BigQuery...\n');
|
|
339
|
-
|
|
340
|
-
const realResult = await v2.execute({
|
|
341
|
-
date: targetDate,
|
|
342
|
-
dryRun: false,
|
|
343
|
-
logger
|
|
344
|
-
});
|
|
345
|
-
|
|
346
|
-
console.log('\nReal execution results:');
|
|
347
|
-
console.log(` Completed: ${realResult.summary.completed}`);
|
|
348
|
-
console.log(` Skipped: ${realResult.summary.skipped}`);
|
|
349
|
-
console.log(` Blocked: ${realResult.summary.blocked}`);
|
|
350
|
-
console.log(` Errors: ${realResult.summary.errors}`);
|
|
351
|
-
|
|
352
|
-
if (realResult.completed.length > 0) {
|
|
353
|
-
console.log('\nCompleted computations:');
|
|
354
|
-
for (const c of realResult.completed) {
|
|
355
|
-
console.log(` ā
${c.name}: ${c.resultCount} results in ${c.duration}ms`);
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
if (realResult.errors.length > 0) {
|
|
360
|
-
console.log('\nErrors:');
|
|
361
|
-
for (const e of realResult.errors) {
|
|
362
|
-
console.log(` ā ${e.name}: ${e.error}`);
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
console.log('\nā
Real execution test complete!\n');
|
|
367
|
-
|
|
368
|
-
return { targetDate, result: realResult };
|
|
369
|
-
|
|
370
|
-
} catch (e) {
|
|
371
|
-
console.log(`\nā Real execution test failed: ${e.message}`);
|
|
372
|
-
console.log(e.stack);
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
// ============================================================================
|
|
377
|
-
// TEST 7: DEPENDENT COMPUTATION EXECUTION
|
|
378
|
-
// ============================================================================
|
|
379
|
-
async function testDependentExecution(previousResult) {
|
|
380
|
-
console.log('\n=== TEST: DEPENDENT COMPUTATION EXECUTION ===\n');
|
|
381
|
-
|
|
382
|
-
if (!previousResult?.targetDate) {
|
|
383
|
-
console.log('ā ļø No previous execution result. Skipping dependent test.\n');
|
|
384
|
-
return;
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
const { targetDate, result: prevResult } = previousResult;
|
|
388
|
-
|
|
389
|
-
// Check if the dependency (PopularInvestorProfileMetrics) was completed
|
|
390
|
-
const depCompleted = prevResult.completed.find(c =>
|
|
391
|
-
c.name.includes('profilemetrics')
|
|
392
|
-
);
|
|
393
|
-
|
|
394
|
-
if (!depCompleted) {
|
|
395
|
-
console.log('ā ļø Dependency (PopularInvestorProfileMetrics) was not completed.');
|
|
396
|
-
console.log(' Cannot test dependent computation.\n');
|
|
397
|
-
return;
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
console.log(`Dependency completed: ${depCompleted.name}`);
|
|
401
|
-
console.log(` Results: ${depCompleted.resultCount}`);
|
|
402
|
-
console.log(` Duration: ${depCompleted.duration}ms`);
|
|
403
|
-
|
|
404
|
-
try {
|
|
405
|
-
const v2 = require('../../index');
|
|
406
|
-
|
|
407
|
-
// Now try to run the dependent computation
|
|
408
|
-
console.log(`\n--- Running Dependent Computation (Pass 2) ---`);
|
|
409
|
-
|
|
410
|
-
// Re-analyze to see the updated state
|
|
411
|
-
const report = await v2.analyze({ date: targetDate, logger });
|
|
412
|
-
|
|
413
|
-
console.log('\nPost-Pass-1 analysis:');
|
|
414
|
-
console.log(` Runnable: ${report.runnable.map(c => c.name).join(', ') || 'none'}`);
|
|
415
|
-
console.log(` Blocked: ${report.blocked.map(c => c.name).join(', ') || 'none'}`);
|
|
416
|
-
console.log(` Skipped: ${report.skipped.map(c => c.name).join(', ') || 'none'}`);
|
|
417
|
-
|
|
418
|
-
// Check if RiskAssessment is now runnable
|
|
419
|
-
const riskRunnable = report.runnable.find(c =>
|
|
420
|
-
c.name.includes('riskassessment')
|
|
421
|
-
);
|
|
422
|
-
|
|
423
|
-
if (riskRunnable) {
|
|
424
|
-
console.log(`\nā
PopularInvestorRiskAssessment is now RUNNABLE!`);
|
|
425
|
-
console.log(` Reason: ${riskRunnable.reason}`);
|
|
426
|
-
|
|
427
|
-
// Execute Pass 2
|
|
428
|
-
console.log('\nExecuting Pass 2...');
|
|
429
|
-
const pass2Result = await v2.execute({
|
|
430
|
-
date: targetDate,
|
|
431
|
-
pass: 2,
|
|
432
|
-
dryRun: false,
|
|
433
|
-
logger
|
|
434
|
-
});
|
|
435
|
-
|
|
436
|
-
console.log('\nPass 2 results:');
|
|
437
|
-
console.log(` Completed: ${pass2Result.summary.completed}`);
|
|
438
|
-
console.log(` Errors: ${pass2Result.summary.errors}`);
|
|
439
|
-
|
|
440
|
-
if (pass2Result.completed.length > 0) {
|
|
441
|
-
for (const c of pass2Result.completed) {
|
|
442
|
-
console.log(` ā
${c.name}: ${c.resultCount} results in ${c.duration}ms`);
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
if (pass2Result.errors.length > 0) {
|
|
447
|
-
for (const e of pass2Result.errors) {
|
|
448
|
-
console.log(` ā ${e.name}: ${e.error}`);
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
} else {
|
|
452
|
-
const riskBlocked = report.blocked.find(c => c.name.includes('riskassessment'));
|
|
453
|
-
const riskSkipped = report.skipped.find(c => c.name.includes('riskassessment'));
|
|
454
|
-
|
|
455
|
-
if (riskBlocked) {
|
|
456
|
-
console.log(`\nā ļø PopularInvestorRiskAssessment is still BLOCKED`);
|
|
457
|
-
console.log(` Reason: ${riskBlocked.reason}`);
|
|
458
|
-
} else if (riskSkipped) {
|
|
459
|
-
console.log(`\nā
PopularInvestorRiskAssessment already completed (skipped)`);
|
|
460
|
-
} else {
|
|
461
|
-
console.log(`\nā ļø Could not find PopularInvestorRiskAssessment in report`);
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
console.log('\nā
Dependent computation test complete!\n');
|
|
466
|
-
|
|
467
|
-
} catch (e) {
|
|
468
|
-
console.log(`\nā Dependent execution test failed: ${e.message}`);
|
|
469
|
-
console.log(e.stack);
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
// ============================================================================
|
|
474
|
-
// RUN ALL TESTS
|
|
475
|
-
// ============================================================================
|
|
476
|
-
async function main() {
|
|
477
|
-
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
478
|
-
console.log('ā Computation System v2 - Framework Tests ā');
|
|
479
|
-
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
480
|
-
|
|
481
|
-
// Core framework tests
|
|
482
|
-
await testManifestBuilding();
|
|
483
|
-
await testComputationValidation();
|
|
484
|
-
await testSchemaRegistry();
|
|
485
|
-
await testQueryBuilder();
|
|
486
|
-
await testDryRun();
|
|
487
|
-
|
|
488
|
-
// Real data tests (writes to BigQuery!)
|
|
489
|
-
const execResult = await testRealExecution();
|
|
490
|
-
await testDependentExecution(execResult);
|
|
491
|
-
|
|
492
|
-
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
493
|
-
console.log('ā Tests Complete ā');
|
|
494
|
-
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
main().catch(e => {
|
|
498
|
-
console.error('Test failed:', e);
|
|
499
|
-
process.exit(1);
|
|
500
|
-
});
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview Quick Real Execution Test
|
|
3
|
-
*
|
|
4
|
-
* Run with: node test/test-real-execution.js
|
|
5
|
-
*
|
|
6
|
-
* This tests real execution and dependency handling.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
// Set up environment
|
|
10
|
-
process.env.GCP_PROJECT_ID = process.env.GCP_PROJECT_ID || 'stocks-12345';
|
|
11
|
-
process.env.BIGQUERY_DATASET_ID = process.env.BIGQUERY_DATASET_ID || 'bulltrackers_data';
|
|
12
|
-
|
|
13
|
-
const logger = {
|
|
14
|
-
log: (level, message) => {
|
|
15
|
-
const timestamp = new Date().toISOString().slice(11, 19);
|
|
16
|
-
console.log(`[${timestamp}] ${level.padEnd(5)} ${message}`);
|
|
17
|
-
}
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
async function main() {
|
|
21
|
-
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
22
|
-
console.log('ā Computation System v2 - Real Execution Test ā');
|
|
23
|
-
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n');
|
|
24
|
-
|
|
25
|
-
const v2 = require('../../index');
|
|
26
|
-
|
|
27
|
-
// Step 1: Verify pass assignment
|
|
28
|
-
console.log('=== STEP 1: Verify Pass Assignment ===\n');
|
|
29
|
-
const manifest = await v2.getManifest();
|
|
30
|
-
|
|
31
|
-
const profileMetrics = manifest.find(m => m.name === 'popularinvestorprofilemetrics');
|
|
32
|
-
const riskAssessment = manifest.find(m => m.name === 'popularinvestorriskassessment');
|
|
33
|
-
|
|
34
|
-
console.log(`PopularInvestorProfileMetrics: Pass ${profileMetrics?.pass}`);
|
|
35
|
-
console.log(`PopularInvestorRiskAssessment: Pass ${riskAssessment?.pass}`);
|
|
36
|
-
console.log(`Dependencies: ${riskAssessment?.dependencies?.join(', ')}`);
|
|
37
|
-
|
|
38
|
-
if (riskAssessment?.pass > profileMetrics?.pass) {
|
|
39
|
-
console.log('\nā
Pass assignment correct - dependent is in later pass');
|
|
40
|
-
} else {
|
|
41
|
-
console.log('\nā Pass assignment incorrect!');
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Step 2: Find runnable date
|
|
46
|
-
console.log('\n=== STEP 2: Find Date with Data ===\n');
|
|
47
|
-
|
|
48
|
-
const today = new Date();
|
|
49
|
-
let targetDate = null;
|
|
50
|
-
|
|
51
|
-
for (let i = 0; i < 7; i++) {
|
|
52
|
-
const checkDate = new Date(today);
|
|
53
|
-
checkDate.setDate(today.getDate() - i);
|
|
54
|
-
const dateStr = checkDate.toISOString().slice(0, 10);
|
|
55
|
-
|
|
56
|
-
console.log(`Checking ${dateStr}...`);
|
|
57
|
-
const report = await v2.analyze({ date: dateStr });
|
|
58
|
-
|
|
59
|
-
if (report.runnable.some(c => c.name === 'popularinvestorprofilemetrics')) {
|
|
60
|
-
targetDate = dateStr;
|
|
61
|
-
console.log(`\nā
Found runnable date: ${dateStr}`);
|
|
62
|
-
break;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (!targetDate) {
|
|
67
|
-
console.log('\nā ļø No runnable date found in last 7 days');
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Step 3: Run Pass 1 (ProfileMetrics)
|
|
72
|
-
console.log('\n=== STEP 3: Execute Pass 1 ===\n');
|
|
73
|
-
|
|
74
|
-
const pass1Result = await v2.execute({
|
|
75
|
-
date: targetDate,
|
|
76
|
-
pass: 1,
|
|
77
|
-
computation: 'PopularInvestorProfileMetrics',
|
|
78
|
-
dryRun: false,
|
|
79
|
-
logger
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
console.log('\nPass 1 results:');
|
|
83
|
-
console.log(` Completed: ${pass1Result.summary.completed}`);
|
|
84
|
-
console.log(` Errors: ${pass1Result.summary.errors}`);
|
|
85
|
-
|
|
86
|
-
if (pass1Result.completed.length > 0) {
|
|
87
|
-
const c = pass1Result.completed[0];
|
|
88
|
-
console.log(`\nā
${c.name}: ${c.resultCount} results in ${c.duration}ms`);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (pass1Result.errors.length > 0) {
|
|
92
|
-
console.log('\nā Errors:');
|
|
93
|
-
for (const e of pass1Result.errors) {
|
|
94
|
-
console.log(` - ${e.name}: ${e.error.substring(0, 100)}...`);
|
|
95
|
-
}
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Step 4: Verify RiskAssessment is now unblocked
|
|
100
|
-
console.log('\n=== STEP 4: Check Dependency State ===\n');
|
|
101
|
-
|
|
102
|
-
// Reset executor to reload status
|
|
103
|
-
await v2.reset();
|
|
104
|
-
|
|
105
|
-
const report2 = await v2.analyze({ date: targetDate });
|
|
106
|
-
|
|
107
|
-
const riskRunnable = report2.runnable.find(c => c.name === 'popularinvestorriskassessment');
|
|
108
|
-
const riskBlocked = report2.blocked.find(c => c.name === 'popularinvestorriskassessment');
|
|
109
|
-
const riskSkipped = report2.skipped.find(c => c.name === 'popularinvestorriskassessment');
|
|
110
|
-
|
|
111
|
-
if (riskRunnable) {
|
|
112
|
-
console.log('ā
PopularInvestorRiskAssessment is now RUNNABLE!');
|
|
113
|
-
console.log(` Reason: ${riskRunnable.reason}`);
|
|
114
|
-
} else if (riskBlocked) {
|
|
115
|
-
console.log('ā ļø PopularInvestorRiskAssessment is still BLOCKED');
|
|
116
|
-
console.log(` Reason: ${riskBlocked.reason}`);
|
|
117
|
-
|
|
118
|
-
// Debug: check status
|
|
119
|
-
console.log('\nDebug: Checking if ProfileMetrics result was saved...');
|
|
120
|
-
// The dependency might not be found because status cache was cleared
|
|
121
|
-
} else if (riskSkipped) {
|
|
122
|
-
console.log('ā¹ļø PopularInvestorRiskAssessment already up to date (skipped)');
|
|
123
|
-
} else {
|
|
124
|
-
console.log('ā ļø Could not find PopularInvestorRiskAssessment in analysis');
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Step 5: Run Pass 2 (RiskAssessment)
|
|
128
|
-
if (riskRunnable || !riskBlocked) {
|
|
129
|
-
console.log('\n=== STEP 5: Execute Pass 2 ===\n');
|
|
130
|
-
|
|
131
|
-
const pass2Result = await v2.execute({
|
|
132
|
-
date: targetDate,
|
|
133
|
-
pass: 2,
|
|
134
|
-
dryRun: false,
|
|
135
|
-
logger
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
console.log('\nPass 2 results:');
|
|
139
|
-
console.log(` Completed: ${pass2Result.summary.completed}`);
|
|
140
|
-
console.log(` Skipped: ${pass2Result.summary.skipped}`);
|
|
141
|
-
console.log(` Errors: ${pass2Result.summary.errors}`);
|
|
142
|
-
|
|
143
|
-
if (pass2Result.completed.length > 0) {
|
|
144
|
-
for (const c of pass2Result.completed) {
|
|
145
|
-
console.log(`\nā
${c.name}: ${c.resultCount} results in ${c.duration}ms`);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
if (pass2Result.errors.length > 0) {
|
|
150
|
-
console.log('\nā Errors:');
|
|
151
|
-
for (const e of pass2Result.errors) {
|
|
152
|
-
console.log(` - ${e.name}: ${e.error.substring(0, 200)}...`);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
console.log('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
158
|
-
console.log('ā Test Complete ā');
|
|
159
|
-
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
main().catch(e => {
|
|
163
|
-
console.error('\nā Test failed:', e.message);
|
|
164
|
-
console.error(e.stack);
|
|
165
|
-
process.exit(1);
|
|
166
|
-
});
|