synthesis-tail-scaling.test.ts 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. /**
  2. * Synthesis-tail scaling regressions (#1212).
  3. *
  4. * On a 2M-node graph (Linux kernel) the dynamic-edge synthesis tail OOM'd
  5. * Node's default heap and/or starved the #850 liveness watchdog: the kotlin
  6. * expect/actual pass opened with `getAllNodes()` (hydrating the entire node
  7. * table into one array), and most passes ran start-to-finish with no yield
  8. * points. The fix streams every whole-kind scan, filters the kotlin pass
  9. * SQL-side, and language-gates passes off the files table.
  10. *
  11. * These tests pin the query-level building blocks and the end-to-end kotlin
  12. * bridge so the memory fix can't silently change what gets synthesized.
  13. */
  14. import { describe, it, expect, beforeEach, afterEach } from 'vitest';
  15. import * as fs from 'node:fs';
  16. import * as path from 'node:path';
  17. import * as os from 'node:os';
  18. import { CodeGraph } from '../src';
  19. describe('synthesis-tail scaling (#1212)', () => {
  20. let dir: string;
  21. beforeEach(() => { dir = fs.mkdtempSync(path.join(os.tmpdir(), 'synth-scaling-')); });
  22. afterEach(() => { fs.rmSync(dir, { recursive: true, force: true }); });
  23. it('kotlin expect/actual still bridges through the streamed decorator query', async () => {
  24. fs.writeFileSync(
  25. path.join(dir, 'Platform.kt'),
  26. `package com.example.shared
  27. expect fun platformName(): String
  28. `
  29. );
  30. fs.writeFileSync(
  31. path.join(dir, 'Platform.jvm.kt'),
  32. `package com.example.shared
  33. actual fun platformName(): String = "JVM"
  34. `
  35. );
  36. const cg = await CodeGraph.init(dir);
  37. await cg.indexAll();
  38. const db = (cg as any).db.db;
  39. const edges = db
  40. .prepare(
  41. `SELECT e.source, e.target FROM edges e
  42. WHERE json_extract(e.metadata,'$.synthesizedBy') = 'kotlin-expect-actual'`
  43. )
  44. .all();
  45. expect(edges.length).toBeGreaterThanOrEqual(1);
  46. cg.close();
  47. });
  48. it('iterateNodesByLanguageWithDecorator matches getAllNodes().filter exactly', async () => {
  49. fs.writeFileSync(
  50. path.join(dir, 'A.kt'),
  51. `package p
  52. actual fun realActual(): Int = 1
  53. `
  54. );
  55. // TypeScript decorator whose name CONTAINS "actual" — the SQL LIKE
  56. // pre-filter must not surface it as a kotlin actual.
  57. fs.writeFileSync(
  58. path.join(dir, 'b.ts'),
  59. `function actual(target: object): void {}
  60. class C {
  61. m(): number { return 1; }
  62. }
  63. `
  64. );
  65. const cg = await CodeGraph.init(dir);
  66. await cg.indexAll();
  67. const queries = (cg as unknown as { queries: import('../src/db/queries').QueryBuilder }).queries;
  68. const streamed = [...queries.iterateNodesByLanguageWithDecorator('kotlin', 'actual')]
  69. .filter((n) => n.decorators?.includes('actual'))
  70. .map((n) => n.id)
  71. .sort();
  72. const reference = queries
  73. .getAllNodes()
  74. .filter((n) => n.language === 'kotlin' && !!n.decorators?.includes('actual'))
  75. .map((n) => n.id)
  76. .sort();
  77. expect(streamed).toEqual(reference);
  78. expect(reference.length).toBeGreaterThanOrEqual(1); // the fixture really has one
  79. cg.close();
  80. });
  81. it('getDistinctFileLanguages reports exactly the languages present', async () => {
  82. fs.writeFileSync(path.join(dir, 'x.ts'), 'export const a = 1;\n');
  83. fs.writeFileSync(path.join(dir, 'y.py'), 'def f():\n return 1\n');
  84. const cg = await CodeGraph.init(dir);
  85. await cg.indexAll();
  86. const queries = (cg as unknown as { queries: import('../src/db/queries').QueryBuilder }).queries;
  87. const langs = queries.getDistinctFileLanguages();
  88. expect(langs.has('typescript')).toBe(true);
  89. expect(langs.has('python')).toBe(true);
  90. expect(langs.has('kotlin')).toBe(false);
  91. cg.close();
  92. });
  93. });