4 poin oleh GN⁺ 2024-04-08 | 1 komentar | Bagikan ke WhatsApp
  • pgmock adalah server tiruan PostgreSQL in-memory untuk unit test dan pengujian E2E, dan berjalan di Node.js maupun browser sebagai WebAssembly tanpa dependensi eksternal
  • Pengguna node-postgres dapat terhubung menggunakan objek konfigurasi tanpa membuka port, dan pendekatan ini juga bekerja di browser
  • Di browser, web app tidak bisa membuka port TCP, tetapi tetap dapat menggunakan PostgresMock.createSocket dan konfigurasi node-postgres; jika bundler menganalisis static import, bisa muncul peringatan tentang modul Node.js opsional
  • Implementasinya saat ini menjalankan server PostgreSQL di dalam emulator x86, dengan prioritas pada mencegah perbedaan perilaku antara pengujian dan produksi dibandingkan performa
  • Dalam jangka panjang, jika fork PostgreSQL WASM native sudah matang, rencananya kedua pendekatan akan disediakan, lalu default akan dialihkan ke WASM native

Apa yang disediakan pgmock

  • pgmock adalah server tiruan PostgreSQL in-memory untuk unit test dan pengujian E2E
  • Tidak memerlukan dependensi eksternal dan berjalan di dalam WebAssembly baik di Node.js maupun browser
  • Instalasi bisa dilakukan dengan npm
npm install pgmock

Alur penggunaan dasar

  • Server in-memory dibuat dengan PostgresMock.create(), dan string koneksi bisa didapatkan lewat listen(5432)
import { PostgresMock } from "pgmock";

const mock = await PostgresMock.create();
const connectionString = await mock.listen(5432);
  • Jika menggunakan node-postgres, mock.getNodePostgresConfig() menyediakan objek konfigurasi untuk terhubung tanpa mendengarkan port
  • Setelah selesai, disarankan memanggil mock.destroy() untuk melepaskan resource
mock.destroy();

Dukungan browser dan perbedaannya dengan pglite

  • pgmock sepenuhnya mendukung lingkungan browser
  • Web app tidak bisa membuka port TCP, tetapi dapat menggunakan PostgresMock.createSocket dan konfigurasi node-postgres
  • Jika bundler menganalisis import secara statis, bisa muncul peringatan bahwa modul Node.js opsional tidak ada; contoh konfigurasi Webpack tersedia di examples/web-demo/next.config.mjs
  • Jika Anda hanya ingin menjalankan database di browser, Anda bisa mempertimbangkan pglite
    • pglite lebih cepat dan ringan, tetapi set fitur yang dimilikinya terbatas
    • pgmock dirancang dengan tujuan kesetaraan fitur dengan PostgreSQL produksi yang diinginkan dalam lingkungan pengujian

Cara menjalankan PostgreSQL di WebAssembly

  • Ada dua cara untuk menjalankan PostgreSQL di WebAssembly
  • Pendekatan fork WASM native lebih cepat dan memakai memori jauh lebih sedikit, tetapi hanya mendukung mode single-user serta tidak mendukung koneksi dan ekstensi
  • pgmock saat ini menggunakan pendekatan emulator x86
    • Tujuannya adalah mencegah ketidakcocokan antara pengujian dan produksi
    • Karena dalam pengujian, performa biasanya bukan masalah besar
  • Dalam jangka menengah, jika fork PostgreSQL WASM native sudah matang, ada rencana untuk menyediakan kedua opsi
  • Setelah itu, ada rencana mengalihkan default ke WASM native, dan diperkirakan tidak akan ada banyak breaking change besar selain pada API internal PostgresMock.subtle

Perbedaannya dengan proyek PostgreSQL browser yang sudah ada

  • pgmock menyediakan kompatibilitas fitur penuh di dalam runtime JavaScript dan tidak bergantung pada proxy jaringan untuk komunikasi
  • Dengan mensimulasikan stack jaringan di JavaScript agar bekerja seperti jaringan sungguhan, ia dapat mensimulasikan koneksi TCP bahkan di platform yang tidak mengizinkan akses raw socket

Ekstensibilitas dan proyek terkait

  • Secara teori, image Docker atau database lain juga bisa dijalankan, tetapi belum diuji
  • Implementasi terkait dan proyek fondasi yang disebutkan meliputi
    • v86: emulator x86
    • Supabase & Snaplet: fondasi pendekatan menjalankan PostgreSQL di dalam WebAssembly
    • Stackframe: perusahaan yang disebut memberikan gaji selama pengembangan pgmock

1 komentar

 
GN⁺ 2024-04-08
Komentar Hacker News
  • Selama beberapa bulan, kami di perusahaan sedang membuat versi Postgres in-memory, dan fiturnya setara dengan database produksi
    Keuntungannya adalah tidak memerlukan proses eksternal atau proxy. Jika platform bisa menjalankan WASM, pgmock dapat dijalankan di Node.js maupun browser, dan membuat database baru berisi data mock pun sesederhana membuat objek JavaScript
    Ini sedikit berbeda dari pglite, yang mendorong pgmock untuk dirilis sebagai open source. pgmock menjalankan Postgres asli di dalam emulator x86, sementara pglite mengompilasi fork Postgres langsung menjadi WASM native sehingga lebih cepat dan ringan
    Namun pglite hanya mendukung mode satu pengguna dan sebagian ekstensi, sehingga tidak bisa diakses dengan klien Postgres biasa; ini cukup penting untuk pengujian E2E
    Secara teori, ini bisa diubah agar dapat menjalankan image Docker apa pun di platform WebAssembly; saya penasaran apakah ada target spesifik yang ingin dilihat

    • Karya yang keren. Memang benar PGlite saat ini hanya mendukung satu pengguna, dan ini bisa menjadi masalah untuk dipakai dalam pengujian integrasi di beberapa lingkungan
      Saya sedang memikirkan beberapa cara untuk menambahkan mode multi-koneksi, tetapi sepertinya akan memakan waktu. PGlite juga punya batasan lain terkait mode satu pengguna; misalnya belum mendukung pg_notify, dan itu juga kami rencanakan untuk diperbaiki
      Di sisi lain, proyek ini jauh lebih dekat dengan Postgres sungguhan, jadi besar kemungkinan langsung berfungsi. Proyek-proyek Postgres in-memory seperti ini tampaknya bisa memangkas waktu eksekusi pengujian menjadi seperempat atau kurang, dan punya potensi besar di bidang pengujian
      Ini pandangan saya sebagai orang yang mengerjakan PGlite
    • Ide menjalankan image Docker di WASM tampak menjanjikan untuk berbagai masalah
      Baru-baru ini saya ingin menjalankan pipeline FFMPEG/SoX di sisi klien, tetapi dependensinya terlalu banyak sehingga sulit dikompilasi ulang dengan Emscripten. Saya penasaran apakah pendekatan ini juga bisa membantu kasus seperti itu
    • Jika bisa mendukung ekstensi pgvector, ini bisa menjadi database vektor yang sangat cepat dengan seluruh kekuatan Postgres
      Berkat fitur relasionalnya, metadata kaya yang spesifik domain yang biasanya ada di database relasional dapat ditambahkan dan dikueri bersama
    • Sebagai catatan, demo online tampaknya rusak pada kueri yang tidak disukainya
      Saat menjalankan select foo();, muncul Error.captureStackTrace is not a function, terjadi di Firefox 124.0.2 di Linux
    • Hebat, tetapi bukankah konsep pengujian E2E sendiri berarti menggunakan lingkungan nyata tanpa mengganti komponen dengan mock?
  • Saya penasaran, bukankah cukup menjalankan file Postgres di ramdisk?
    Pembaruan: sepertinya ini dapat berjalan di lingkungan browser/Node sehingga pengujian bisa membuat, memperbarui, dan menghapusnya. Saya terlalu backend developer, jadi kurang paham keunggulannya dibanding lingkungan pengembangan umum. Akan bagus jika ada yang bisa menjelaskan di mana, kapan, dan bagaimana ini lebih baik

    • Di dalam emulator pun pada dasarnya hal serupa terjadi. Disk yang diemulasi adalah sistem file 9P in-memory
      Alasan membuatnya dengan WebAssembly adalah agar perilakunya lebih portabel di berbagai platform, arsitektur, hingga browser atau edge environment, serta menjadi konfigurasi tanpa dependensi eksternal yang bahkan tidak memerlukan Docker
      Karena emulator memungkinkan boot langsung dari state yang sudah berjalan, boot database yang diemulasi lebih cepat daripada menyalakan database sungguhan atau container Docker. Namun ini lebih seperti efek samping yang beruntung daripada tujuan desain
    • Saya juga kurang tahu. Sepertinya ada terlalu banyak kode yang tidak perlu seperti emulator, network stack, dan sebagainya
      Saya penasaran kenapa tidak memakai sesuatu seperti https://testcontainers.com/. Apakah container engine sebagai dependensi eksternal memang seburuk itu?
    • Tujuan pengujian E2E adalah menguji sistem dalam keadaan nyata. Karena ini emulasi lingkungan produksi, kita juga bisa memeriksa apa yang terjadi ketika daya dicabut atau disk penuh
      Begitu Anda memasukkan mock ke dalamnya, itu menjadi unit test. Tetap berguna, tetapi tidak sama. Salah satu inti E2E adalah kita tahu pengujiannya akurat karena tidak ada mock. Ini bukan menguji Postgres, melainkan menguji sistem ini setiap kali
      Jika Anda membuat PG untuk sistem embedded, ringan, dan berperforma rendah, ini masuk akal sebagai pengujian verifikasi sebelum pengujian E2E sungguhan yang lambat. Saya juga punya kebutuhan seperti itu
      Di luar itu, ini proyek yang keren, dan tampak seperti alat yang bisa dipakai saat membutuhkan PG shim
    • Ini bisa berguna untuk isolasi pengujian. Saat memindahkan backend Redis ke FakeRedis dalam pengujian, noise di test suite cukup berkurang
      Untuk Postgres kami memakai savepoint, tetapi bahkan di ramdisk pun tidak terlalu cepat
  • Dulu kami menjalankan berbagai server in-memory palsu kustom dalam pengujian. Sekarang kami menjalankan target sungguhan dengan https://testcontainers.com

  • Jika developer Prisma/Node.js hanya menginginkan “Postgres dalam kaleng” untuk pengembangan lokal, versi PGlite terbaru yang dijadikan server, pglite-server, mungkin lebih cocok: https://github.com/kamilogorek/pglite-server
    Ini lebih cepat dan dapat menyimpan data di sistem file, tetapi saat penggunaan berat kurang stabil dibanding server pengujian E2E berbasis emulator x86 penuh. pglite-server hanya memakai memori 150MB, sedangkan pgmock-server memakai 830MB
    Cukup checkout .env.local baru dengan dotenv dan ubah DATABASE_URL pada semua skrip eksekusi package.json nextjs/prisma
    DATABASE_URL="postgresql://postgres@localhost:5432/awesomeproject"
    "db:pushlocal": "dotenv -e .env.local -- pnpm prisma db push"
    Sangat mudah dipasang ke proyek apa pun, dan bisa dimengerti mengapa Neon mensponsori area ini

  • Saya tidak bermaksud merusak suasana, tetapi saya tidak berencana memakai ini.
    Untuk aplikasi sederhana mungkin bisa berjalan, tetapi ketika kompleksitas meningkat—misalnya ada risiko deadlock atau ketergantungan pada bentuk database—perbedaan perilaku kecil saja bisa berkembang menjadi masalah fatal, sehingga nilainya berkurang.
    Belakangan ini saya lebih menyukai lingkungan E2E dengan keterbatasan sumber daya, karena runner pengujian lokal memberi kesempatan untuk gagal ketika seseorang menulis kode yang sangat tidak efisien.
    Selain itu, pendekatan membuat database menjadi snapshot setelah beberapa detik lalu mendistribusikan snapshot itu ke partisi pengujian sangat cepat, dan sering kali menghemat beberapa menit dalam test suite.
    Ini ide yang menarik dan pengalaman belajar yang bagus, tetapi menurut saya pengguna sasarannya terbatas.

  • Judulnya agak membingungkan. Kalau “dibuat di perusahaan”, dengan asumsi memakai sumber daya perusahaan, bukankah hak kekayaan intelektual proyek ini berada pada pemberi kerja?
    Kalau begitu, saya penasaran apakah secara teknis boleh dirilis sebagai open source.

    • Karena ini startup, merilisnya sebagai open source semudah mendapatkan persetujuan dari anggota tim lainnya.
    • Repositorinya dimiliki Stackframe dan file LICENSE mencantumkan Copyright 2024 Stackframe.. Sepertinya penulis bekerja di Stackframe.
  • Saya penasaran bagaimana ini dibandingkan dengan mode kompatibilitas Postgres di H2.

    • Bisa saja saya salah, tetapi sepertinya H2 tidak bisa memakai stored procedure PostgreSQL.
  • Cukup keren. Kalau bisa dijawab, ada beberapa hal yang ingin saya ketahui.
    Saya penasaran apa yang membuat perusahaan membuat proyek ini, apakah menjalankan Postgres di container Docker terlalu lambat.
    Saya juga ingin tahu bagaimana konfigurasi CI untuk pengujian E2E berubah sebelum dan sesudah mengintegrasikan pgmock ke dalam alur.
    Saya juga penasaran apakah proses berpindah ke solusi ini sulit.

  • Jika data produksi didump lalu semua data sensitif dihapus, kemudian tabel yang tidak diperlukan seperti tabel log di-truncate, Anda akan mendapatkan salinan yang bagus untuk pengembangan.
    Tinggal direplikasi ke development, QA, E2E, dan sebagainya. Yang dibutuhkan E2E justru extension, trigger, function, view, index, data itu.

  • Saya penasaran kenapa tidak cukup memakai Docker saja dan menyediakan database pengujian terpisah.
    Elixir melakukan itu, dan framework pengujiannya membungkus tiap pengujian dalam transaksi lalu melakukan rollback untuk isolasi. Menarik juga mengetahui apa keunggulan pendekatan ini.