Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
"sharp": "^0.35.3",
"tsx": "4.23.12",
"typescript": "6.0.3",
"undici": "^7.29.0",
"wrangler": "4.125.0"
},
"overrides": {
Expand Down
5 changes: 5 additions & 0 deletions scripts/orbit-mcp-authorization-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,18 @@ import { tmpdir } from 'node:os';
import path from 'node:path';
import { after, before, describe, test } from 'node:test';
import { reserveWorkerPorts } from './orbit-test-ports';
import { useFreshConnectionPerRequest } from './support/test-http';
import { BACKUP_SCHEMA_VERSION } from '../src/server/backup/dynamic-backup';
import {
createOpaqueToken,
parseOpaqueToken,
verifyOpaqueToken,
} from '../src/server/identity/tokens';

/* Havuzda bekleyen bir keep-alive soketi, bu dosyanın spawnSync
* bloklarından sağ çıkmıyor; gerekçesi support/test-http.ts içinde. */
useFreshConnectionPerRequest();

const ROOT = process.cwd();
const WRANGLER = path.join(ROOT, 'node_modules', 'wrangler', 'bin', 'wrangler.js');
const CONFIG = 'wrangler.test.jsonc';
Expand Down
5 changes: 5 additions & 0 deletions scripts/orbit-site-authorization-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { tmpdir } from 'node:os';
import path from 'node:path';
import { after, before, describe, test } from 'node:test';
import { reserveWorkerPorts } from './orbit-test-ports';
import { useFreshConnectionPerRequest } from './support/test-http';
import {
normalizeSiteAuthorizationScopes,
parseSiteAuthorizationScopes,
Expand All @@ -30,6 +31,10 @@ import {
} from '../src/server/identity/site-authorization-request';
import { siteConsentPage } from '../src/server/http/site-consent-page';

/* Havuzda bekleyen bir keep-alive soketi, bu dosyanın spawnSync
* bloklarından sağ çıkmıyor; gerekçesi support/test-http.ts içinde. */
useFreshConnectionPerRequest();

const ROOT = process.cwd();
const WRANGLER = path.join(ROOT, 'node_modules', 'wrangler', 'bin', 'wrangler.js');
const CONFIG = 'wrangler.test.jsonc';
Expand Down
5 changes: 5 additions & 0 deletions scripts/orbit-site-client-registration-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,13 @@ import path from 'node:path';
import { after, before, describe, test } from 'node:test';

import { reserveWorkerPorts } from './orbit-test-ports';
import { useFreshConnectionPerRequest } from './support/test-http';
import { createOpaqueToken, hmacDigest, randomBase64Url } from '../src/server/identity/tokens';

/* Havuzda bekleyen bir keep-alive soketi, bu dosyanın spawnSync
* bloklarından sağ çıkmıyor; gerekçesi support/test-http.ts içinde. */
useFreshConnectionPerRequest();

const ROOT = process.cwd();
const WRANGLER = path.join(ROOT, 'node_modules', 'wrangler', 'bin', 'wrangler.js');
const CONFIG = 'wrangler.slice1-test.jsonc';
Expand Down
5 changes: 5 additions & 0 deletions scripts/orbit-site-signin-e2e-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,18 @@ import { tmpdir } from 'node:os';
import path from 'node:path';
import { after, before, describe, test } from 'node:test';
import { reserveWorkerPorts } from './orbit-test-ports';
import { useFreshConnectionPerRequest } from './support/test-http';
import {
createOpaqueToken,
hmacDigest,
randomBase64Url,
sha256Base64Url,
} from '../src/server/identity/tokens';

/* Havuzda bekleyen bir keep-alive soketi, bu dosyanın spawnSync
* bloklarından sağ çıkmıyor; gerekçesi support/test-http.ts içinde. */
useFreshConnectionPerRequest();

const ROOT = process.cwd();
const WRANGLER = path.join(ROOT, 'node_modules', 'wrangler', 'bin', 'wrangler.js');
const CONFIG = 'wrangler.slice1-test.jsonc';
Expand Down
5 changes: 5 additions & 0 deletions scripts/orbit-slice1-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { tmpdir } from 'node:os';
import path from 'node:path';
import { after, before, describe, test } from 'node:test';
import { reserveWorkerPorts } from './orbit-test-ports';
import { useFreshConnectionPerRequest } from './support/test-http';
import {
CSRF_COOKIE,
CSRF_HEADER,
Expand All @@ -21,6 +22,10 @@ import {
} from '../src/server/identity/tokens';
import { LEGAL_LAST_UPDATED } from '../src/data/legal';

/* Havuzda bekleyen bir keep-alive soketi, bu dosyanın spawnSync
* bloklarından sağ çıkmıyor; gerekçesi support/test-http.ts içinde. */
useFreshConnectionPerRequest();

const ROOT = process.cwd();
const WRANGLER = path.join(ROOT, 'node_modules', 'wrangler', 'bin', 'wrangler.js');
const CONFIG = 'wrangler.slice1-test.jsonc';
Expand Down
5 changes: 5 additions & 0 deletions scripts/orbit-slice3-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@ import { tmpdir } from 'node:os';
import path from 'node:path';
import { after, before, describe, test } from 'node:test';
import { reserveWorkerPorts } from './orbit-test-ports';
import { useFreshConnectionPerRequest } from './support/test-http';
import { loadManifest, verifyManifest } from './orbit-slice3-manifest';

/* Havuzda bekleyen bir keep-alive soketi, bu dosyanın spawnSync
* bloklarından sağ çıkmıyor; gerekçesi support/test-http.ts içinde. */
useFreshConnectionPerRequest();

const ROOT = process.cwd();
const WRANGLER = path.join(ROOT, 'node_modules', 'wrangler', 'bin', 'wrangler.js');
const CONFIG = 'wrangler.slice1-test.jsonc';
Expand Down
5 changes: 5 additions & 0 deletions scripts/orbit-slice4-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { mkdtemp, readdir, readFile, rm } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { after, before, describe, test } from 'node:test';
import { reserveWorkerPorts } from './orbit-test-ports';
import { useFreshConnectionPerRequest } from './support/test-http';
import { createEntityId } from '../src/server/foundation/ids';
import { createOpaqueToken, hmacDigest, randomBase64Url, sha256Base64Url } from '../src/server/identity/tokens';
import { canonicalJson } from '../src/server/publication/content';
Expand All @@ -15,6 +16,10 @@ import {
type DynamicBackup,
} from '../src/server/backup/dynamic-backup';

/* Havuzda bekleyen bir keep-alive soketi, bu dosyanın spawnSync
* bloklarından sağ çıkmıyor; gerekçesi support/test-http.ts içinde. */
useFreshConnectionPerRequest();

const ROOT = process.cwd();
const WRANGLER = path.join(ROOT, 'node_modules', 'wrangler', 'bin', 'wrangler.js');
const TSX = path.join(ROOT, 'node_modules', 'tsx', 'dist', 'cli.mjs');
Expand Down
5 changes: 5 additions & 0 deletions scripts/orbit-slice5-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { mkdtemp, rm } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { after, before, describe, test } from 'node:test';
import { reserveWorkerPorts } from './orbit-test-ports';
import { useFreshConnectionPerRequest } from './support/test-http';
import { createEntityId } from '../src/server/foundation/ids';
import { createOpaqueToken, hmacDigest, randomBase64Url, sha256Base64Url } from '../src/server/identity/tokens';
import { canonicalJson } from '../src/server/publication/content';
Expand All @@ -17,6 +18,10 @@ import { verifyDynamicBackup } from '../src/server/backup/dynamic-backup';
import { ImageTransformError, inspectImage, transformImage } from '../src/server/media/image-processor';
import sharp from 'sharp';

/* Havuzda bekleyen bir keep-alive soketi, bu dosyanın spawnSync
* bloklarından sağ çıkmıyor; gerekçesi support/test-http.ts içinde. */
useFreshConnectionPerRequest();

const ROOT = process.cwd();
const WRANGLER = path.join(ROOT, 'node_modules', 'wrangler', 'bin', 'wrangler.js');
const TSX = path.join(ROOT, 'node_modules', 'tsx', 'dist', 'cli.mjs');
Expand Down
5 changes: 5 additions & 0 deletions scripts/support/d1-test-worker-harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ import { mkdtemp, rm } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import path from 'node:path';
import { reserveWorkerPorts } from '../orbit-test-ports';
import { useFreshConnectionPerRequest } from './test-http';

/* Havuzda bekleyen bir keep-alive soketi, bu dosyanın spawnSync
* bloklarından sağ çıkmıyor; gerekçesi support/test-http.ts içinde. */
useFreshConnectionPerRequest();

const ROOT = process.cwd();
const WRANGLER = path.join(ROOT, 'node_modules', 'wrangler', 'bin', 'wrangler.js');
Expand Down
79 changes: 79 additions & 0 deletions scripts/support/test-http.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/**
* Yerel test worker'larına giden fetch'lerin bağlantı politikası.
*
* Belirti şuydu: CI'da ara sıra, bir testin ilk `fetch`'i hiçbir iddiaya
* varmadan 3-4 ms içinde düşüyordu.
*
* TypeError: fetch failed
* cause: SocketError: other side closed (UND_ERR_SOCKET)
* socket: { bytesWritten: 370, bytesRead: 1631 }
*
* `bytesRead` sıfır değil: soket daha önce bir yanıt taşımış, yani bu yeni
* kurulan bir bağlantı değil, undici'nin havuzundan gelen bir keep-alive
* bağlantısı. Sunucu onu kapatmış (FIN), istemci ölü sokete yazmış.
*
* Neden istemci FIN'i görmüyor: bu test dosyaları worker ayaktayken
* `spawnSync` ile ikinci wrangler süreçleri koşturuyor (migration, importer,
* d1 execute). `spawnSync` olay döngüsünü saniyelerce tamamen durduruyor.
* O sürede undici ne soketin FIN'ini işleyebiliyor ne de kendi boşta kalma
* zamanlayıcısını (varsayılan 4 sn) çalıştırıp soketi havuzdan atabiliyor.
* `spawnSync` döner dönmez gelen `fetch` isteği aynı senkron adımda ölü
* sokete yazılıyor. Sunucu tarafında da bir güvence yok: workerd yanıtta
* `Keep-Alive` başlığı göndermiyor, yani boşta kalan bir bağlantıyı ne
* zaman kapatacağını istemciye hiç söylemiyor.
*
* HTTP/1.1'de bunun sağlıklı bir çözümü yok: yazmadan önce bağlantının
* hâlâ açık olup olmadığını bilmenin yolu yoktur. Normal istemciler bunu
* "güvenli isteği bir kez tekrar dene" ile örter; testte hatayı örtmek
* istemiyoruz. Kalan tek sağlam seçenek bağlantıyı hiç yeniden
* kullanmamak: `pipelining: 0` undici'de keep-alive'ı kapatır, her istek
* kendi bağlantısını açar ve yarış ortadan kalkar. Yerelde birkaç düzine
* istek için maliyeti ölçülemeyecek kadar küçük.
*/
import { Agent, setGlobalDispatcher } from 'undici';
import type { Dispatcher } from 'undici';

let installed = false;

/* Node'un global `fetch`'i dispatcher'ı `Symbol.for('undici.globalDispatcher.1')`
* üzerinden okuyor; undici paketinin `setGlobalDispatcher`'ı aynı sembole
* yazdığı için yerleşik fetch de bu ayarı görüyor. */
export function useFreshConnectionPerRequest(): void {
if (installed) return;
const agent = new Agent({ pipelining: 0 });
setGlobalDispatcher(agent);
assertDispatcherInstalled(agent);
installed = true;
}

/* Bekçi: ayarın gerçekten yerleşip yerleşmediğini kontrol eder.
*
* `setGlobalDispatcher` global bir sembole yazıyor ve Node'un yerleşik
* `fetch`'i onu okuyor. Bugün (Node 26 / undici 7) iki sembol de —
* `undici.globalDispatcher.1` ve `.2` — aynı nesneyi gösteriyor. Yarın
* paket ile Node'un sembolleri ayrışırsa çağrı sessizce hiçbir şey yapmaz:
* keep-alive geri gelir, flake geri gelir ve hiçbir test kırılmaz, çünkü
* bu yalnızca ara sıra düşen bir yarışı geri açar.
*
* Sessiz bozulmayı gürültülü hataya çeviriyoruz: yerleşmediyse testler
* daha ilk satırda dursun. */
function assertDispatcherInstalled(expected: Dispatcher): void {
const seen = [
Symbol.for('undici.globalDispatcher.1'),
Symbol.for('undici.globalDispatcher.2'),
].filter((symbol) => symbol in globalThis);

const missed = seen.filter(
(symbol) => (globalThis as Record<symbol, unknown>)[symbol] !== expected,
);

if (seen.length === 0 || missed.length > 0) {
throw new Error(
'Test fetch bağlantı politikası yerleşmedi: undici setGlobalDispatcher ' +
"Node'un yerleşik fetch'inin okuduğu sembole yazmıyor. Keep-alive " +
'yeniden kullanımı geri döner ve UND_ERR_SOCKET flake\'i yeniden ' +
'başlar. support/test-http.ts içindeki gerekçeye bak; undici ve Node ' +
'sürümlerinin uyumunu kontrol et.',
);
}
}