@playwright-orchestrator/pg 1.0.5 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,7 @@
1
1
  export interface CreateArgs {
2
2
  connectionString: string;
3
3
  tableNamePrefix: string;
4
+ sslCa?: string;
5
+ sslCert?: string;
6
+ sslKey?: string;
4
7
  }
@@ -1,2 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
1
+ export {};
package/dist/index.d.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import { Command } from '@commander-js/extra-typings';
2
- import { CreateArgs } from './create-args';
3
- import { PostgreSQLAdapter } from './postgresql-adapter';
4
- export { PostgreSQLAdapter as PostreSQLAdapter };
5
- export declare function factory(args: CreateArgs): PostgreSQLAdapter;
2
+ import { CreateArgs } from './create-args.js';
3
+ import { PostgreSQLAdapter } from './postgresql-adapter.js';
4
+ export declare function factory(args: CreateArgs): Promise<PostgreSQLAdapter>;
6
5
  export declare function createOptions(command: Command): void;
7
6
  export declare const description = "PostgreSQL storage adapter";
package/dist/index.js CHANGED
@@ -1,16 +1,18 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.description = exports.PostreSQLAdapter = void 0;
4
- exports.factory = factory;
5
- exports.createOptions = createOptions;
6
- const postgresql_adapter_1 = require("./postgresql-adapter");
7
- Object.defineProperty(exports, "PostreSQLAdapter", { enumerable: true, get: function () { return postgresql_adapter_1.PostgreSQLAdapter; } });
8
- function factory(args) {
9
- return new postgresql_adapter_1.PostgreSQLAdapter(args);
1
+ import { Option } from '@commander-js/extra-typings';
2
+ import { PostgreSQLAdapter } from './postgresql-adapter.js';
3
+ export async function factory(args) {
4
+ return new PostgreSQLAdapter(args);
10
5
  }
11
- function createOptions(command) {
6
+ export function createOptions(command) {
12
7
  command
13
- .option('--table-name-prefix <string>', 'Tables name prefix', 'playwright_orchestrator')
14
- .requiredOption('--connection-string <string>', 'Connection string');
8
+ .addOption(new Option('--table-name-prefix <string>', 'Tables name prefix')
9
+ .default('playwright_orchestrator')
10
+ .env('TABLE_NAME_PREFIX'))
11
+ .addOption(new Option('--ssl-ca <string>', 'SSL CA').env('SSL_CA'))
12
+ .addOption(new Option('--ssl-cert <string>', 'SSL certificate').env('SSL_CERT'))
13
+ .addOption(new Option('--ssl-key <string>', 'SSL key').env('SSL_KEY'))
14
+ .addOption(new Option('--connection-string <string>', 'Connection string')
15
+ .makeOptionMandatory()
16
+ .env('CONNECTION_STRING'));
15
17
  }
16
- exports.description = 'PostgreSQL storage adapter';
18
+ export const description = 'PostgreSQL storage adapter';
@@ -1,10 +1,10 @@
1
1
  import { TestItem, TestRunInfo, Adapter, TestRunConfig } from '@playwright-orchestrator/core';
2
- import { CreateArgs } from './create-args';
2
+ import { CreateArgs } from './create-args.js';
3
3
  export declare class PostgreSQLAdapter extends Adapter {
4
4
  private readonly configTable;
5
5
  private readonly testsTable;
6
6
  private readonly pool;
7
- constructor({ connectionString, tableNamePrefix }: CreateArgs);
7
+ constructor({ connectionString, tableNamePrefix, sslCa, sslCert, sslKey }: CreateArgs);
8
8
  getNextTest(runId: string, config: TestRunConfig): Promise<TestItem | undefined>;
9
9
  finishTest(runId: string, test: TestItem): Promise<void>;
10
10
  failTest(runId: string, test: TestItem): Promise<void>;
@@ -1,14 +1,23 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PostgreSQLAdapter = void 0;
4
- const core_1 = require("@playwright-orchestrator/core");
5
- const pg_1 = require("pg");
6
- class PostgreSQLAdapter extends core_1.Adapter {
7
- constructor({ connectionString, tableNamePrefix }) {
1
+ import { Adapter, RunStatus, TestStatus } from '@playwright-orchestrator/core';
2
+ import pg from 'pg';
3
+ export class PostgreSQLAdapter extends Adapter {
4
+ configTable;
5
+ testsTable;
6
+ pool;
7
+ constructor({ connectionString, tableNamePrefix, sslCa, sslCert, sslKey }) {
8
8
  super();
9
- this.pool = new pg_1.Pool({ connectionString });
10
- this.configTable = (0, pg_1.escapeIdentifier)(`${tableNamePrefix}_test_runs`);
11
- this.testsTable = (0, pg_1.escapeIdentifier)(`${tableNamePrefix}_tests`);
9
+ const config = { connectionString };
10
+ config.ssl = sslCa || sslCert || sslKey ? {} : undefined;
11
+ if (sslCa) {
12
+ config.ssl.ca = sslCa;
13
+ }
14
+ if (sslCert && sslKey) {
15
+ config.ssl.cert = sslCert;
16
+ config.ssl.key = sslKey;
17
+ }
18
+ this.pool = new pg.Pool(config);
19
+ this.configTable = pg.escapeIdentifier(`${tableNamePrefix}_test_runs`);
20
+ this.testsTable = pg.escapeIdentifier(`${tableNamePrefix}_tests`);
12
21
  }
13
22
  async getNextTest(runId, config) {
14
23
  const client = await this.pool.connect();
@@ -28,7 +37,7 @@ class PostgreSQLAdapter extends core_1.Adapter {
28
37
  FROM next_test
29
38
  WHERE t.run_id = $1 AND t.order_num = next_test.order_num
30
39
  RETURNING *`,
31
- values: [runId, core_1.TestStatus.Ready, core_1.TestStatus.Running],
40
+ values: [runId, TestStatus.Ready, TestStatus.Ongoing],
32
41
  });
33
42
  await client.query('COMMIT');
34
43
  if (result.rowCount === 0)
@@ -44,10 +53,10 @@ class PostgreSQLAdapter extends core_1.Adapter {
44
53
  }
45
54
  }
46
55
  async finishTest(runId, test) {
47
- await this.updateTestStatus(runId, test, core_1.TestStatus.Passed);
56
+ await this.updateTestStatus(runId, test, TestStatus.Passed);
48
57
  }
49
58
  async failTest(runId, test) {
50
- await this.updateTestStatus(runId, test, core_1.TestStatus.Failed);
59
+ await this.updateTestStatus(runId, test, TestStatus.Failed);
51
60
  }
52
61
  async updateTestStatus(runId, test, status) {
53
62
  await this.pool.query({
@@ -62,7 +71,7 @@ class PostgreSQLAdapter extends core_1.Adapter {
62
71
  await this.pool.query({
63
72
  name: 'insert-config',
64
73
  text: `INSERT INTO ${this.configTable} (id, status, config) VALUES ($1, $2, $3)`,
65
- values: [runId, core_1.RunStatus.Created, JSON.stringify({ ...testRun.config, args })],
74
+ values: [runId, RunStatus.Created, JSON.stringify({ ...testRun.config, args })],
66
75
  });
67
76
  const tests = this.flattenTestRun(testRun.testRun);
68
77
  const fields = ['order_num', 'file', 'line', 'character', 'project', 'timeout'];
@@ -103,35 +112,59 @@ class PostgreSQLAdapter extends core_1.Adapter {
103
112
  updated TIMESTAMP NOT NULL DEFAULT NOW(),
104
113
  PRIMARY KEY (run_id, order_num),
105
114
  FOREIGN KEY (run_id) REFERENCES ${this.configTable}(id)
106
- );`);
115
+ );
116
+ CREATE INDEX IF NOT EXISTS status_idx ON ${this.testsTable}(status);`);
107
117
  }
108
118
  async startShard(runId) {
109
- // Avoid updating updated field as shard can be started multiple times in uncertain order and time.
110
- const result = await this.pool.query({
111
- name: 'update-start-config',
112
- text: `UPDATE ${this.configTable}
113
- SET status =
114
- CASE
115
- WHEN status IN ($1, $2) THEN $2
116
- ELSE $3
117
- END
118
- WHERE id = $4
119
- RETURNING *`,
120
- values: [core_1.RunStatus.Finished, core_1.RunStatus.Rerun, core_1.RunStatus.Run, runId],
121
- });
122
- if (result.rowCount === 0) {
123
- throw new Error(`Run ${runId} not found`);
119
+ const client = await this.pool.connect();
120
+ try {
121
+ await client.query('BEGIN');
122
+ let result = await client.query({
123
+ text: `
124
+ SELECT *
125
+ FROM ${this.configTable}
126
+ WHERE id = $1
127
+ FOR UPDATE`,
128
+ values: [runId],
129
+ });
130
+ if (result.rowCount === 0) {
131
+ throw new Error(`Run ${runId} not found`);
132
+ }
133
+ const { updated: updatedBefore, status: statusBefore } = result.rows[0];
134
+ if (statusBefore === RunStatus.Created || statusBefore === RunStatus.Finished) {
135
+ await client.query({
136
+ text: `
137
+ UPDATE ${this.testsTable}
138
+ SET updated = NOW(), status = $3
139
+ WHERE run_id = $1 AND status = $2 AND updated <= $4;`,
140
+ values: [runId, TestStatus.Failed, TestStatus.Ready, updatedBefore],
141
+ });
142
+ // using str interpolation for case statement to avoid casting ints to strings
143
+ result = await client.query({
144
+ text: `
145
+ UPDATE ${this.configTable}
146
+ SET status = (CASE
147
+ WHEN status = $2 THEN ${RunStatus.Run}
148
+ ELSE ${RunStatus.RepeatRun}
149
+ END),
150
+ updated = NOW()
151
+ WHERE id = $1
152
+ RETURNING *;`,
153
+ values: [runId, RunStatus.Created],
154
+ });
155
+ }
156
+ await client.query('COMMIT');
157
+ const { updated, status, config } = result.rows[0];
158
+ const mappedConfig = { ...config, updated: updated.getTime(), status };
159
+ return mappedConfig;
160
+ }
161
+ catch (e) {
162
+ await client.query('ROLLBACK');
163
+ throw e;
164
+ }
165
+ finally {
166
+ client.release();
124
167
  }
125
- const { updated, status, config } = result.rows[0];
126
- const mappedConfig = { ...config, updated: updated.getTime(), status };
127
- await this.pool.query({
128
- name: 'update-tests-status',
129
- text: `UPDATE ${this.testsTable}
130
- SET status = $1
131
- WHERE run_id = $2 AND status = $3 AND updated < $4`,
132
- values: [core_1.TestStatus.Ready, runId, core_1.TestStatus.Failed, updated],
133
- });
134
- return mappedConfig;
135
168
  }
136
169
  async finishShard(runId) {
137
170
  // set 'updated' field to current time as test run exhausted all tests
@@ -142,7 +175,7 @@ class PostgreSQLAdapter extends core_1.Adapter {
142
175
  SET status = $1,
143
176
  updated = NOW()
144
177
  WHERE id = $2`,
145
- values: [core_1.RunStatus.Finished, runId],
178
+ values: [RunStatus.Finished, runId],
146
179
  });
147
180
  }
148
181
  async dispose() {
@@ -151,4 +184,3 @@ class PostgreSQLAdapter extends core_1.Adapter {
151
184
  await this.pool.end();
152
185
  }
153
186
  }
154
- exports.PostgreSQLAdapter = PostgreSQLAdapter;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playwright-orchestrator/pg",
3
- "version": "1.0.5",
3
+ "version": "1.1.1",
4
4
  "keywords": [],
5
5
  "author": "Rostyslav Kudrevatykh",
6
6
  "license": "Apache-2.0",
@@ -13,18 +13,18 @@
13
13
  "dist"
14
14
  ],
15
15
  "dependencies": {
16
+ "@commander-js/extra-typings": "^13.0.0",
17
+ "@playwright-orchestrator/core": "^1.1.0",
18
+ "commander": "^13.0.0",
16
19
  "pg": "^8.13.1"
17
20
  },
18
21
  "devDependencies": {
19
22
  "@types/pg": "^8.11.0"
20
23
  },
21
- "peerDependencies": {
22
- "@commander-js/extra-typings": "^13.0.0",
23
- "@playwright-orchestrator/core": "^1.0.0"
24
- },
24
+ "main": "dist/index.js",
25
+ "type": "module",
25
26
  "exports": {
26
27
  ".": {
27
- "types": "./dist/index.d.ts",
28
28
  "default": "./dist/index.js"
29
29
  }
30
30
  },
package/dist/package.json DELETED
@@ -1,34 +0,0 @@
1
- {
2
- "name": "@playwright-orchestrator/pg",
3
- "version": "1.0.5",
4
- "keywords": [],
5
- "author": "Rostyslav Kudrevatykh",
6
- "license": "Apache-2.0",
7
- "description": "Playwright orchestrator PostgreSQL plugin",
8
- "repository": {
9
- "type": "git",
10
- "url": "git+https://github.com/rostmanrk/playwright-orchestrator.git"
11
- },
12
- "files": [
13
- "dist"
14
- ],
15
- "dependencies": {
16
- "pg": "^8.13.1"
17
- },
18
- "devDependencies": {
19
- "@types/pg": "^8.11.0"
20
- },
21
- "peerDependencies": {
22
- "@commander-js/extra-typings": "^13.0.0",
23
- "@playwright-orchestrator/core": "^1.0.0"
24
- },
25
- "exports": {
26
- ".": {
27
- "types": "./dist/index.d.ts",
28
- "default": "./dist/index.js"
29
- }
30
- },
31
- "scripts": {
32
- "prepare": "cp ../../LICENSE.md ./"
33
- }
34
- }
@@ -1 +0,0 @@
1
- {"root":["../create-args.ts","../index.ts","../postgresql-adapter.ts","../package.json"],"version":"5.7.2"}