コンテンツにスキップ

Node.jsガイド

@osmem/coreosmem-serverを子プロセスとして起動し、アドレスが報告されるとテストにクローンのURLを渡します。npmがoptional dependenciesから対応するplatform package(@osmem/darwin-arm64@osmem/linux-x64など)もinstallするため、binaryを別途設定する必要はありません。このページでは、VitestとJest、素のnode:test、そしてオプションを扱います。

ターミナルウィンドウ
npm install --save-dev @osmem/core @opensearch-project/opensearch

@osmem/coreはローカルサーバーとテスト用helperを提供し、@opensearch-project/opensearchはアプリ側と同じ公式クライアントです。npmが現在のOSとCPUに合うoptional binary packageを選びます。

起動し、schemaを登録して検索する

Section titled “起動し、schemaを登録して検索する”

launcherは子プロセスを1つ起動します。requestでindexを作ってdocumentを登録し、同じserver URLを公式クライアントに渡します。

import { OsmemServer } from "@osmem/core";
import { Client } from "@opensearch-project/opensearch";
const server = await OsmemServer.start({ japanese: false });
try {
await server.request("PUT", "/products", {
mappings: { properties: { name: { type: "text", fields: { keyword: { type: "keyword" } } } } },
});
await server.request("PUT", "/products/_doc/1", { name: "Red Apple" });
const client = new Client({ node: server.url });
const result = await client.search({ index: "products", body: { query: { match: { name: "apple" } } } });
console.log(result.body.hits.hits);
} finally {
await server.close();
}

fixtureが大きくなったらstartにseed directoryを渡します。共通seed形式ならmappingやdocumentをレビューしやすく、言語間でも共有できます。

ファイルごとに1サーバー、状態を変えるテストはclone

Section titled “ファイルごとに1サーバー、状態を変えるテストはclone”

beforeAllでサーバーを起動し、afterAllで閉じます。withCloneはクローンを作り、それを渡して関数を実行し、終わったらクローンを削除します。

documentの追加・削除、mappingの変更、indexの作成・削除など、indexの状態を変えるテストではcloneを使います。検索だけを行うテストなら、server.urlを直接使えます。

import { OsmemServer } from "@osmem/core";
import { Client } from "@opensearch-project/opensearch";
let server;
beforeAll(async () => {
server = await OsmemServer.start({ seed: ["./testdata/seed"], freeze: true });
});
afterAll(() => server.close());
test("adds a product", async () => {
await server.withClone(async (clone) => {
const client = new Client({ node: clone.url });
await client.index({ index: "products", id: "x", body: { name: "new" } });
const res = await client.get({ index: "products", id: "x" });
expect(res.body.found).toBe(true);
});
});

同じコードがJestでもVitestでも動きます。node:testでは、beforeAll/afterAllの代わりにnode:testbefore/afterを使います。

自分で閉じたい場合は、server.clone()がクローンのオブジェクトを返します。clone.urlが、どのOpenSearchクライアントにも渡せるアドレスです。読み取りだけのテストはserver.urlを直接使えます。

OsmemServer.start(options)が受け付けるもの:

オプション 意味
seed シードディレクトリか.ndjsonファイル、またはその配列。指定順に読み込む(形式)
freeze ベースへの書き込みを即座に拒否する(指定しなければ最初のクローンで凍結される)
japanese falseでkuromojiを無効にする。デフォルトはtrue
addr listenするアドレス。デフォルトは127.0.0.1:0
binary osmem-serverのパス。プラットフォームパッケージより優先される
startupTimeoutMs デフォルトは30000
inheritStderr falseでサーバーの標準エラーを表示しない

server.request(method, path, body)は任意のJSONリクエストをベースに送り、エラーステータスなら例外を投げます。/_osmem_countに対するアサーションに便利です。

環境変数OSMEM_SERVER_BINは、プラットフォームパッケージより優先されます。ローカルでビルドしたサーバーで試すときに使います。

require("@osmem/core")は、同じstartメソッドを持つ{ OsmemServer }を返します。実装はESモジュールとして遅延ロードされるので、startはいつもどおりawaitしてください。

子プロセスには--parent-pidと、パイプでつないだ標準入力が渡されます。終了するのは、テストプロセスが終わって標準入力が閉じたとき、親のpidが消えたとき、あるいはserver.close()が呼ばれたときです。close()は標準入力を閉じ、5秒経っても終わらなければプロセスをkillします。テストランナーがクラッシュしても、サーバーは残りません。

  • テストごとに新しいserver: 各テスト内でOsmemServer.start({ seed })を呼び、finallyで閉じます。境界は単純ですが、起動とseedを繰り返します。
  • fileまたはworkerごとに1つのserver: 上の例のようにbeforeAllで起動し、afterAllで閉じます。読み取り専用テストはserver.urlを直接使えます。
  • 副作用のあるテスト: document、mapping、indexの状態を変えるなら、server.withClone(...)server.clone()でseed済みbaseをforkします。cloneは隔離され、閉じれば変更は破棄されます。withCloneならassertionが失敗しても後始末されます。

書き込み可能なcloneをテスト間で共有しないでください。並列テストでは、それぞれ専用cloneを作ります。