Skip to content

Commit

Permalink
implement support of zincsearch
Browse files Browse the repository at this point in the history
  • Loading branch information
Blankll committed Jul 15, 2023
1 parent 8fc9d92 commit 0938134
Show file tree
Hide file tree
Showing 8 changed files with 182 additions and 52 deletions.
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ module.exports = () => {
binaryLocation: '', // optional
clusterName: 'jest-search-local',
nodeName: 'jest-search-local',
zincAdmin: 'admin',
zincPassword: 'Complexpass#123',
indexes: [
{
name: 'index-name',
Expand Down Expand Up @@ -83,6 +85,11 @@ module.exports = () => {

- indexes: specify the configuration like index name, and mapping of indexes that you want to create during the startup, and indexes will get deleted once test is finished: default: `[]`

- zincAdmin:<string> zincsearch requires pass env `ZINC_FIRST_ADMIN_USER` when starting zincsearch, default: `admin`,

- zincPassword: <string> : zincsearch requires pass env `ZINC_FIRST_ADMIN_PASSWORD` when starting zincsearch, default: `Complexpass#123`




**3. create `jest-global-setup.js`**
Expand Down Expand Up @@ -136,4 +143,3 @@ beforeAll(async () => {
### Known issues

1. Windows is not on the support list yet, I didn't see the necessity of it yet, feel free to reach out if you have the needs to use it on Windows, then will prioritize it
2. ZincSearch is working in progress
4 changes: 2 additions & 2 deletions package-lock.json

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

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@geek-fun/jest-search",
"version": "0.0.9",
"version": "1.0.0",
"main": "dist/src/index.js",
"types": "dist/src/index.d.ts",
"description": "Jest preset for running tests with local search platform",
Expand Down
2 changes: 1 addition & 1 deletion src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ export const DISABLE_PROXY = {
export const ARTIFACTS = {
ES: 'https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch',
OS: 'https://artifacts.opensearch.org/releases/bundle/opensearch',
ZINC: 'https://github.com/zinclabs/zinc/releases/download',
ZINC: 'https://github.com/zincsearch/zincsearch/releases/download',
};
90 changes: 57 additions & 33 deletions src/engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,30 @@ import { execSync } from 'child_process';
import path from 'path';
import { debug } from './debug';
import { ARTIFACTS, DISABLE_PROXY } from './constants';
import { downloadZinc, startZinc } from './zinc';

export enum EngineType {
ZINC = 'zinc',
ZINCSEARCH = 'zincsearch',
ELASTICSEARCH = 'elasticsearch',
OPENSEARCH = 'opensearch',
}

type IndexBody = { name: string; body?: unknown; mappings?: unknown };
export type EngineOptions = {
engine: EngineType;
version: string;
binaryLocation: string;
clusterName: string;
nodeName: string;
port: number;
indexes: Array<{ name: string; body: unknown }>;
zincAdmin: string;
zincPassword: string;
indexes: Array<IndexBody>;
};
type ConfiguredOptions = Omit<EngineOptions, 'binaryLocation'> & { binaryFilepath: string };
export type ConfiguredOptions = Omit<EngineOptions, 'binaryLocation'> & { binaryFilepath: string };

let server: execa.ExecaChildProcess;
let engineOptions: ConfiguredOptions;
// 'https://artifacts.opensearch.org/releases/core/opensearch/2.8.0/opensearch-min-2.8.0-linux-x64.tar.gz'

const getEngineResourceURL = async (engine: EngineType, version: string) => {
const { sysName, arch } = await platform();
const engines: {
Expand All @@ -39,15 +42,19 @@ const getEngineResourceURL = async (engine: EngineType, version: string) => {
: `${ARTIFACTS.ES}-${version}.tar.gz`,
[EngineType.OPENSEARCH]: () =>
`${ARTIFACTS.OS}/${version}/opensearch-${version}-linux-${arch.replace('86_', '')}.tar.gz`,
[EngineType.ZINC]: () =>
`${ARTIFACTS.ZINC}/v${version}/zinc_${version}_${sysName}_${arch}.tar.gz`,
[EngineType.ZINCSEARCH]: () =>
`${ARTIFACTS.ZINC}/v${version}/zincsearch_${version}_${sysName}_${arch}.tar.gz`,
};

return engines[engine]();
};
const prepareEngine = async (engine: EngineType, version: string, binaryLocation: string) => {
const url = await getEngineResourceURL(engine, version);
const binaryFilepath = `${binaryLocation}/${engine}-${version}`;
if (engine === EngineType.ZINCSEARCH) {
await downloadZinc(url, binaryFilepath);
return binaryFilepath;
}

debug(`checking if binary exists: ${binaryFilepath}`);
if (!(await isFileExists(binaryFilepath))) {
Expand All @@ -64,16 +71,20 @@ const createIndexes = async () => {
const { indexes, port, engine } = engineOptions;

const curlCommands: {
[engineType: string]: (indexItem: { name: string; body: unknown }) => string;
[engineType: string]: (indexItem: IndexBody) => string;
} = {
[EngineType.ELASTICSEARCH]: ({ name, body }: { name: string; body: unknown }) =>
[EngineType.ELASTICSEARCH]: ({ name, body }: IndexBody) =>
`curl -XPUT "http://localhost:${port}/${name}" -H "Content-Type: application/json" -d'${JSON.stringify(
body
)}'`,
[EngineType.OPENSEARCH]: ({ name, body }: { name: string; body: unknown }) =>
[EngineType.OPENSEARCH]: ({ name, body }: IndexBody) =>
`curl -XPUT "http://localhost:${port}/${name}" -H "Content-Type: application/json" -d'${JSON.stringify(
body
)}'`,
[EngineType.ZINCSEARCH]: (index: IndexBody) =>
`curl -XPUT "http://localhost:${port}/api/index" -u ${engineOptions.zincAdmin}:${
engineOptions.zincPassword
} -H "Content-Type: application/json" -d'${JSON.stringify(index)}'`,
};
debug('creating indexes');
await Promise.all(
Expand All @@ -84,39 +95,40 @@ const createIndexes = async () => {
const start = async () => {
const { engine, version, binaryFilepath, clusterName, nodeName, port } = engineOptions;
debug(`Starting ${engine} ${version}, ${binaryFilepath}`);
const startMatrix: { [key: string]: Array<string> } = {
[EngineType.ELASTICSEARCH]: [
'-p',
`${binaryFilepath}/server-pid`,
`-Ecluster.name=${clusterName}`,
`-Enode.name=${nodeName}`,
`-Ehttp.port=${port}`,
`-Expack.security.enabled=false`,
],
[EngineType.OPENSEARCH]: [
'-p',
`${binaryFilepath}/server-pid`,
`-Ecluster.name=${clusterName}`,
`-Enode.name=${nodeName}`,
`-Ehttp.port=${port}`,
`-Eplugins.security.disabled=true`,
],
};
server = execa(`${binaryFilepath}/bin/${engine}`, startMatrix[engine], { all: true });
if (engine === EngineType.ZINCSEARCH) {
server = startZinc(engineOptions);
} else {
server = execa(
`${binaryFilepath}/bin/${engine}`,
[
'-p',
`${binaryFilepath}/server-pid`,
`-Ecluster.name=${clusterName}`,
`-Enode.name=${nodeName}`,
`-Ehttp.port=${port}`,
engine === EngineType.OPENSEARCH
? `-Eplugins.security.disabled=true`
: `-Expack.security.enabled=false`,
],
{ all: true }
);
}

await waitForLocalhost(port);
await waitForLocalhost(engine, port);
debug(`${engine} is running on port: ${port}, pid: ${server.pid}`);
await createIndexes();

debug(`indexes created`);
};

const cleanupIndices = async (): Promise<void> => {
const { port, indexes } = engineOptions;
const { engine, port, indexes, zincAdmin, zincPassword } = engineOptions;
if (indexes.length <= 0) return;
debug(' deleting indexes');
const result = execSync(
`curl -s -X DELETE http://localhost:${port}/${indexes.map(({ name }) => name).join(',')}`,
engine === EngineType.ZINCSEARCH
? `curl -s -X DELETE http://localhost:${port}/api/index/* -u ${zincAdmin}:${zincPassword}`
: `curl -s -X DELETE http://localhost:${port}/${indexes.map(({ name }) => name).join(',')}`,
DISABLE_PROXY
);

Expand Down Expand Up @@ -156,9 +168,21 @@ export const startEngine = async ({
clusterName = 'jest-search-local',
nodeName = 'jest-search-local',
indexes = [],
zincAdmin = 'admin',
zincPassword = 'Complexpass#123',
}: Partial<EngineOptions> = {}) => {
const binaryFilepath = await prepareEngine(engine, version, binaryLocation);
engineOptions = { engine, version, port, clusterName, nodeName, binaryFilepath, indexes };
engineOptions = {
engine,
version,
port,
clusterName,
nodeName,
binaryFilepath,
indexes,
zincAdmin,
zincPassword,
};
// start engine
await start();
};
Expand Down
9 changes: 6 additions & 3 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,27 @@ import execa from 'execa';
import { execSync } from 'child_process';
import { debug } from './debug';
import { DISABLE_PROXY } from './constants';
import { EngineType } from './engine';

export const waitForLocalhost = async (port: number, retries = 60) => {
export const waitForLocalhost = async (engine: EngineType, port: number, retries = 60) => {
debug(`checking the local engine startup: ${retries}`);
await new Promise((resolve) => setTimeout(() => resolve(0), 2000));
if (retries <= 0) {
throw new Error('failed start search engine');
}

const response = execSync(
`curl -s -o /dev/null -i -w "%{http_code}" "http://localhost:${port}" || true`,
engine === EngineType.ZINCSEARCH
? `curl -s -o /dev/null -i -w "%{http_code}" "http://localhost:${port}/es/" || true`
: `curl -s -o /dev/null -i -w "%{http_code}" "http://localhost:${port}" || true`,
DISABLE_PROXY
);

const statusCode = parseInt(response.toString('utf-8'), 10);
debug(`curl response: ${statusCode}`);

if (statusCode !== 200) {
await waitForLocalhost(port, retries - 1);
await waitForLocalhost(engine, port, retries - 1);
} else {
debug('engine started');
}
Expand Down
40 changes: 40 additions & 0 deletions src/zinc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import execa from 'execa';
import { ConfiguredOptions, EngineType } from './engine';
import { debug } from './debug';
import { isFileExists } from './utils';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import download from 'download-tarball';

export const startZinc = ({
binaryFilepath,
engine,
port,
zincAdmin,
zincPassword,
}: Pick<
ConfiguredOptions,
'binaryFilepath' | 'engine' | 'port' | 'zincAdmin' | 'zincPassword'
>) => {
return execa(`${binaryFilepath}/${engine}`, {
all: true,
env: {
ZINC_SERVER_PORT: `${port}`,
ZINC_FIRST_ADMIN_USER: zincAdmin,
ZINC_FIRST_ADMIN_PASSWORD: zincPassword,
ZINC_SHARD_NUM: '1',
ZINC_DATA_PATH: `${binaryFilepath}/data`,
},
});
};

export const downloadZinc = async (url: string, binaryFilepath: string) => {
debug(`checking if binary exists: ${binaryFilepath}`);
if (!(await isFileExists(binaryFilepath))) {
debug(`downloading binary, url: ${url}, path: ${binaryFilepath}`);
await download({ url, dir: binaryFilepath });
debug(`Downloaded ${EngineType.ZINCSEARCH}`);
} else {
debug(`${EngineType.ZINCSEARCH} already downloaded`);
}
};
Loading

0 comments on commit 0938134

Please sign in to comment.