- pgmock यूनिट टेस्ट और E2E टेस्ट के लिए एक इन-memory PostgreSQL mock server है, जो बिना किसी external dependency के Node.js और browser में WebAssembly पर चलता है
node-postgres उपयोगकर्ता एक config object लेकर connect कर सकते हैं जो port नहीं खोलता, और यह तरीका browser में भी काम करता है
- browser में web app TCP port नहीं खोल सकता, लेकिन
PostgresMock.createSocket और node-postgres config का इस्तेमाल किया जा सकता है; अगर bundler static import को analyze करे तो optional Node.js module warning आ सकती है
- implementation अभी x86 emulator के भीतर PostgreSQL server चलाने का तरीका इस्तेमाल करता है, और performance से ज़्यादा टेस्ट और production के बीच behavior difference को रोकने को प्राथमिकता देता है
- लंबे समय में, native PostgreSQL WASM fork mature होने पर दोनों तरीके उपलब्ध कराने और बाद में native WASM को default में बदलने की योजना है
pgmock क्या प्रदान करता है
- pgmock यूनिट टेस्ट और E2E टेस्ट के लिए एक in-memory PostgreSQL mock server है
- इसे किसी external dependency की ज़रूरत नहीं है, और यह Node.js तथा browser दोनों में WebAssembly के भीतर चलता है
- installation npm से की जा सकती है
npm install pgmock
बुनियादी उपयोग प्रवाह
- in-memory server
PostgresMock.create() से बनाया जा सकता है, और listen(5432) से connection string प्राप्त की जा सकती है
import { PostgresMock } from "pgmock";
const mock = await PostgresMock.create();
const connectionString = await mock.listen(5432);
- अगर
node-postgres इस्तेमाल कर रहे हों, तो mock.getNodePostgresConfig() ऐसा config object देता है जिससे port listen किए बिना connect किया जा सकता है
- काम पूरा होने पर resource मुक्त करने के लिए
mock.destroy() कॉल करने की सिफारिश की जाती है
mock.destroy();
browser support और pglite से अंतर
pgmock browser environment को पूरी तरह support करता है
- web app TCP port नहीं खोल सकता, लेकिन
PostgresMock.createSocket और node-postgres config का उपयोग किया जा सकता है
- अगर bundler import को statically analyze करे, तो optional Node.js module न होने की warning आ सकती है; Webpack config का उदाहरण
examples/web-demo/next.config.mjs में है
- अगर browser में सिर्फ database चलाना हो, तो pglite पर विचार किया जा सकता है
- pglite ज़्यादा तेज़ और हल्का है, लेकिन इसका feature set सीमित है
pgmock को test environment में production PostgreSQL के साथ feature parity को लक्ष्य बनाकर डिज़ाइन किया गया है
WebAssembly में PostgreSQL चलाने का तरीका
- WebAssembly में PostgreSQL चलाने के दो तरीके हैं
- native WASM fork तरीका ज़्यादा तेज़ है और काफ़ी कम memory इस्तेमाल करता है, लेकिन यह केवल single-user mode support करता है और connection व extension support नहीं देता
pgmock अभी x86 emulator वाला तरीका इस्तेमाल करता है
- इसका उद्देश्य test और production के बीच mismatch को रोकना है
- क्योंकि testing में performance आम तौर पर बड़ी समस्या नहीं होती
- मध्यम अवधि में native PostgreSQL WASM fork mature होने पर दोनों विकल्प देने की योजना है
- इसके बाद native WASM को default में बदलने की योजना है, और उम्मीद है कि
PostgresMock.subtle internal API को छोड़कर बड़े breaking change ज़्यादा नहीं होंगे
मौजूदा browser PostgreSQL projects से अंतर
pgmock JavaScript runtime के भीतर full feature compatibility देता है और communication के लिए network proxy पर निर्भर नहीं करता
- यह JavaScript में network stack को simulate करके उसे वास्तविक network की तरह काम करने देता है, और raw socket access की अनुमति न देने वाले platform पर भी TCP connection को simulate कर सकता है
विस्तार क्षमता और संबंधित projects
- सैद्धांतिक रूप से अन्य Docker image या database भी चलाए जा सकते हैं, लेकिन उनका परीक्षण नहीं हुआ है
- संबंधित implementation और आधार projects के रूप में निम्न का उल्लेख किया गया है
- v86: x86 emulator
- Supabase & Snaplet: WebAssembly के भीतर PostgreSQL चलाने के तरीके की बुनियाद
- Stackframe: वह कंपनी जिसका उल्लेख
pgmock के विकास के दौरान वेतन देने वाली कंपनी के रूप में किया गया है
1 टिप्पणियां
Hacker News टिप्पणियाँ
पिछले कुछ महीनों से कंपनी में in-memory Postgres का एक वर्शन बना रहे थे, और इसमें प्रोडक्शन डेटाबेस के बराबर फीचर समानता है
इसका फायदा यह है कि किसी external process या proxy की ज़रूरत नहीं होती। अगर प्लेटफ़ॉर्म WASM चला सकता है, तो Node.js या ब्राउज़र में भी pgmock चलाया जा सकता है, और mock data के साथ नया डेटाबेस बनाना भी JavaScript object बनाने जितना आसान है
यह pglite से थोड़ा अलग है, जिसने pgmock को open source करने की प्रेरणा दी। pgmock मूल Postgres को x86 emulator के अंदर चलाता है, जबकि pglite Postgres fork को native WASM में सीधे compile करता है, इसलिए वह ज़्यादा तेज़ और हल्का है
लेकिन pglite सिर्फ single-user mode और कुछ extensions को ही support करता है, इसलिए उससे सामान्य Postgres client के ज़रिए connect नहीं किया जा सकता, और E2E testing में यह काफ़ी महत्वपूर्ण है
सिद्धांत रूप में इसे इस तरह बदला जा सकता है कि WebAssembly प्लेटफ़ॉर्म पर कोई भी Docker image चले, तो जानना चाहूँगा कि लोग कौन-से खास targets देखना चाहते हैं
multi-connection mode जोड़ने के कुछ तरीके सोचे हैं, लेकिन इसमें थोड़ा समय लगेगा। PGlite में single-user mode से जुड़ी कुछ और सीमाएँ भी हैं, जैसे यह अभी
pg_notifysupport नहीं करता, और इसे भी ठीक करने की योजना हैदूसरी तरफ यह प्रोजेक्ट असली Postgres के कहीं ज़्यादा क़रीब है, इसलिए इसके बस काम कर जाने की संभावना अधिक है। ऐसे in-memory Postgres प्रोजेक्ट्स testing runtime को एक-चौथाई से भी कम कर सकते हैं, और testing क्षेत्र में इनकी बड़ी संभावना है
यह PGlite पर काम करने वाले की नज़र से राय है
हाल में client side पर FFMPEG/SoX pipeline चलानी थी, लेकिन dependencies इतनी ज़्यादा थीं कि Emscripten से दोबारा compile करना आसान नहीं था। सोच रहा हूँ कि क्या यह approach ऐसे cases में भी मदद कर सकती है
relational features की वजह से उस समृद्ध domain-specific metadata को भी जोड़ा और query किया जा सकता है जो आम तौर पर relational database में होता है
select foo();चलाने परError.captureStackTrace is not a functionआता है, और यह Linux के Firefox 124.0.2 में हो रहा हैसोच रहा हूँ कि Postgres फ़ाइल को बस ramdisk पर रखकर चलाना काफ़ी क्यों नहीं है
अपडेट: लगता है यह browser/Node environment में चल सकता है, इसलिए tests इसे create·update·delete कर सकते हैं। शायद मैं बहुत backend developer हूँ, इसलिए सामान्य development environment की तुलना में इसका फ़ायदा ठीक से समझ नहीं पा रहा। अगर कोई बताए कि यह कहाँ, कब और कैसे बेहतर है तो अच्छा होगा
इसे WebAssembly में बनाने की वजह यह है कि platform, architecture, browser और edge environments तक behavior को ज़्यादा portable बनाया जा सके, और सेटअप में Docker जैसी किसी external dependency की भी ज़रूरत न रहे
emulator को पहले से चलती हुई state से सीधे boot कराया जा सकता है, इसलिए emulated database को boot करना असली database या Docker container उठाने से तेज़ है। हालाँकि यह कोई design goal कम और एक lucky side effect ज़्यादा है
सोचता हूँ https://testcontainers.com/ जैसी चीज़ क्यों न इस्तेमाल की जाए। क्या container engine का external dependency होना वाकई इतनी बुरी बात है?
जैसे ही आप उसमें mocks ठूँसते हैं, वह unit test बन जाता है। उसका असर हो सकता है, लेकिन वह वही चीज़ नहीं है। E2E की एक बड़ी खासियत यह है कि उसमें mocks नहीं होते, इसलिए आप जानते हैं कि test सटीक है। इसमें Postgres को test नहीं किया जा रहा, बल्कि हर बार इस सिस्टम को test किया जा रहा है
अगर आप embedded, lightweight, low-performance systems के लिए PG बना रहे हैं, तो धीमे असली E2E tests से पहले verification test के रूप में यह समझ में आता है। मेरे पास भी ऐसा एक use case है
इसके अलावा यह शानदार प्रोजेक्ट है, और जब PG shim की ज़रूरत हो तब इस्तेमाल करने लायक tool लगता है
Postgres के लिए savepoint इस्तेमाल कर रहे हैं, लेकिन ramdisk पर भी वह इतना तेज़ नहीं है
पहले tests में तरह-तरह के custom fake in-memory server चलाते थे। आजकल https://testcontainers.com से असली targets चलाते हैं
अगर Prisma/Node.js developer को local development के लिए बस “डिब्बाबंद Postgres” चाहिए, तो हाल में आया PGlite का serverized वर्शन pglite-server बेहतर हो सकता है: https://github.com/kamilogorek/pglite-server
यह तेज़ है और file system पर data persist भी कर सकता है, लेकिन भारी usage पर यह full x86 emulator-आधारित E2E test server की तुलना में कम stable है। pglite-server सिर्फ 150MB memory इस्तेमाल करता है, जबकि pgmock-server ने 830MB लिया
बस dotenv से नया
.env.localcheckout करें और सभी nextjs/prismapackage.jsonrun scripts मेंDATABASE_URLबदल देंDATABASE_URL="postgresql://postgres@localhost:5432/awesomeproject""db:pushlocal": "dotenv -e .env.local -- pnpm prisma db push"इसे किसी भी प्रोजेक्ट में बहुत आसानी से जोड़ा जा सकता है, और यह भी समझ में आता है कि Neon इस क्षेत्र को sponsor क्यों कर रहा है
मैं इस पर ठंडा पानी नहीं डालना चाहता, लेकिन मैं खुद इसे इस्तेमाल करने वाला नहीं हूँ
साधारण applications के लिए यह काम कर सकता है, लेकिन जहाँ deadlock का जोखिम हो या जटिलता database के स्वरूप पर निर्भर करती हो, वहाँ behavior में छोटा-सा फर्क भी गंभीर समस्या बन सकता है, इसलिए इसकी उपयोगिता कम हो जाती है
इन दिनों मैं resource-constrained E2E environments को पसंद करता हूँ। इससे local test runner को यह मौका मिलता है कि अगर किसी ने बहुत ही inefficient code लिख दिया हो तो वह टूटकर सामने आ जाए
इसके अलावा, database का कुछ सेकंड बाद snapshot बनाकर उस snapshot को test partition में deploy करने का तरीका बहुत तेज़ है, और इसने कई बार test suite से कई मिनट कम किए हैं
विचार दिलचस्प है और सीखने के लिहाज़ से अच्छा अनुभव भी होगा, लेकिन मुझे लगता है कि इसके उपयोगकर्ता सीमित होंगे
शीर्षक थोड़ा भ्रमित करने वाला है। अगर “कंपनी में बनाया” गया है, तो यह मान लिया जाएगा कि कंपनी के resources इस्तेमाल हुए, ऐसे में इस project की intellectual property नियोक्ता के पास नहीं होनी चाहिए?
अगर ऐसा है, तो तकनीकी रूप से इसे open source के रूप में जारी करना ठीक है या नहीं, यह जानने की उत्सुकता है
Copyright 2024 Stackframe.लिखा है। लगता है कि लेखक Stackframe में काम करता हैयह H2 के Postgres compatibility mode की तुलना में कैसा है, यह जानना दिलचस्प होगा
काफ़ी बढ़िया है। अगर जवाब दे सकें तो कुछ बातें जानना चाहूँगा
कंपनी में यह project बनाने की वजह क्या थी? क्या Docker container में Postgres चलाना बहुत धीमा था?
pgmock को flow में integrate करने से पहले और बाद में E2E tests के लिए CI setup कैसे बदला, यह भी जानना चाहूँगा
यह भी जानना दिलचस्प होगा कि इस solution पर migrate करना मुश्किल था या नहीं
production data को dump करके, फिर सारा sensitive data हटा दें, और log tables जैसी गैर-ज़रूरी tables को truncate कर दें, तो development के लिए एक अच्छी copy मिल जाती है
फिर उसे development, QA, E2E आदि में replicate किया जा सकता है। E2E के लिए ज़रूरी चीज़ें वही extensions, triggers, functions, views, indexes, data हैं
क्या बस Docker का इस्तेमाल करके एक अलग test database नहीं रखा जा सकता?
Elixir में ऐसा ही किया जाता है, और test framework हर test को transaction में wrap करके isolation के लिए rollback कर देता है। इस approach का फ़ायदा क्या है, यह जानना दिलचस्प होगा