4 पॉइंट द्वारा GN⁺ 2024-04-08 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • 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 टिप्पणियां

 
GN⁺ 2024-04-08
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 देखना चाहते हैं

    • शानदार काम है। यह सही है कि PGlite अभी single-user ही support करता है, और कुछ environments में integration testing के लिए यह समस्या हो सकती है
      multi-connection mode जोड़ने के कुछ तरीके सोचे हैं, लेकिन इसमें थोड़ा समय लगेगा। PGlite में single-user mode से जुड़ी कुछ और सीमाएँ भी हैं, जैसे यह अभी pg_notify support नहीं करता, और इसे भी ठीक करने की योजना है
      दूसरी तरफ यह प्रोजेक्ट असली Postgres के कहीं ज़्यादा क़रीब है, इसलिए इसके बस काम कर जाने की संभावना अधिक है। ऐसे in-memory Postgres प्रोजेक्ट्स testing runtime को एक-चौथाई से भी कम कर सकते हैं, और testing क्षेत्र में इनकी बड़ी संभावना है
      यह PGlite पर काम करने वाले की नज़र से राय है
    • WASM में Docker image चलाने का विचार कई समस्याओं के लिए काफ़ी promising लगता है
      हाल में client side पर FFMPEG/SoX pipeline चलानी थी, लेकिन dependencies इतनी ज़्यादा थीं कि Emscripten से दोबारा compile करना आसान नहीं था। सोच रहा हूँ कि क्या यह approach ऐसे cases में भी मदद कर सकती है
    • अगर pgvector extension support हो सके, तो यह Postgres की पूरी ताकत वाला एक बेहद तेज़ vector database बन सकता है
      relational features की वजह से उस समृद्ध domain-specific metadata को भी जोड़ा और query किया जा सकता है जो आम तौर पर relational database में होता है
    • जानकारी के लिए, online demo कुछ नापसंद queries पर टूटता हुआ लगता है
      select foo(); चलाने पर Error.captureStackTrace is not a function आता है, और यह Linux के Firefox 124.0.2 में हो रहा है
    • बढ़िया है, लेकिन क्या E2E testing की मूल अवधारणा यह नहीं है कि components को mocks से बदला न जाए और असली environment का इस्तेमाल हो?
  • सोच रहा हूँ कि Postgres फ़ाइल को बस ramdisk पर रखकर चलाना काफ़ी क्यों नहीं है
    अपडेट: लगता है यह browser/Node environment में चल सकता है, इसलिए tests इसे create·update·delete कर सकते हैं। शायद मैं बहुत backend developer हूँ, इसलिए सामान्य development environment की तुलना में इसका फ़ायदा ठीक से समझ नहीं पा रहा। अगर कोई बताए कि यह कहाँ, कब और कैसे बेहतर है तो अच्छा होगा

    • emulator के अंदर भी मोटे तौर पर यही हो रहा है। emulated disk एक in-memory 9P file system है
      इसे 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 ज़्यादा है
    • मुझे भी ठीक से समझ नहीं आया। इसमें emulator, network stack वगैरह जैसी अनावश्यक code बहुत ज़्यादा लगती है
      सोचता हूँ https://testcontainers.com/ जैसी चीज़ क्यों न इस्तेमाल की जाए। क्या container engine का external dependency होना वाकई इतनी बुरी बात है?
    • E2E testing का मकसद सिस्टम को वास्तविक स्थिति में test करना है। क्योंकि यह production environment का emulation है, इसलिए बिजली खींच लेने या disk भर जाने पर क्या होता है, यह भी देखा जा सकता है
      जैसे ही आप उसमें mocks ठूँसते हैं, वह unit test बन जाता है। उसका असर हो सकता है, लेकिन वह वही चीज़ नहीं है। E2E की एक बड़ी खासियत यह है कि उसमें mocks नहीं होते, इसलिए आप जानते हैं कि test सटीक है। इसमें Postgres को test नहीं किया जा रहा, बल्कि हर बार इस सिस्टम को test किया जा रहा है
      अगर आप embedded, lightweight, low-performance systems के लिए PG बना रहे हैं, तो धीमे असली E2E tests से पहले verification test के रूप में यह समझ में आता है। मेरे पास भी ऐसा एक use case है
      इसके अलावा यह शानदार प्रोजेक्ट है, और जब PG shim की ज़रूरत हो तब इस्तेमाल करने लायक tool लगता है
    • यह test isolation के लिए उपयोगी हो सकता है। Redis backend को tests में FakeRedis पर ले जाने से test suite का काफ़ी noise कम हो गया था
      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.local checkout करें और सभी nextjs/prisma package.json run 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 के रूप में जारी करना ठीक है या नहीं, यह जानने की उत्सुकता है

    • यह एक startup है, इसलिए इसे open source करना टीम के बाकी सदस्यों से approval लेने जितना आसान था
    • repository, Stackframe के ownership में है और LICENSE file में Copyright 2024 Stackframe. लिखा है। लगता है कि लेखक Stackframe में काम करता है
  • यह H2 के Postgres compatibility mode की तुलना में कैसा है, यह जानना दिलचस्प होगा

    • मैं गलत हो सकता हूँ, लेकिन लगता है H2 में PostgreSQL stored procedures इस्तेमाल नहीं किए जा सकते
  • काफ़ी बढ़िया है। अगर जवाब दे सकें तो कुछ बातें जानना चाहूँगा
    कंपनी में यह 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 का फ़ायदा क्या है, यह जानना दिलचस्प होगा