diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 86ccdd7..87d1311 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -23,3 +23,13 @@ jobs: npm test env: CI: true + integration_test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - run: npm ci + - name: Integration test with MySQL image + uses: docker://givery/track-mysql:2.3.2 + with: + entrypoint: mocha + args: integration_test/mysql.test.js diff --git a/integration_test/mysql.test.js b/integration_test/mysql.test.js new file mode 100644 index 0000000..c364017 --- /dev/null +++ b/integration_test/mysql.test.js @@ -0,0 +1,60 @@ +const fs = require("fs").promises; +const os = require("os"); +const expect = require("chai").expect; +const u = require("./util"); + +describe("MySQL test runner", function () { + this.timeout(30000); + + let dir + beforeEach(async () => { + dir = await fs.mkdtemp(os.tmpdir() + "/"); + }); + afterEach(async () => { + await fs.rm(dir, { recursive: true }); + }); + + it("should work", async () => { + await u.write(dir, { + "package.json": u.trimTextBlock(` + { + "scripts": { + "test": "mocha -R track-reporter" + }, + "dependencies": { + "track-db-test-library": "${process.cwd()}", + "mysql": "2.18" + } + } + `), + "test": { + "test.js": u.trimTextBlock(` + const dblib = require("track-db-test-library"); + const runner = new dblib.TestRunner("ja", "test/test.yml"); + runner.runAll(); + `), + "test.yml": u.trimTextBlock(` + client: mysql + testcases: + - title: "[Basic] ใƒ†ใ‚นใƒˆ" + exec: + - CREATE TABLE points(x INTEGER, y INTEGER) + - INSERT INTO points (x, y) VALUES (1, 2) + - SELECT x, y FROM points + check: + equal_to: test/01.csv + `), + "01.csv": u.trimTextBlock(` + x,y + 1,2 + `), + } + }); + + await u.exec("npm install", { cwd: dir }); + const r = await u.exec("npm test", { cwd: dir }); + + expect(r.ok).to.be.true; + expect(r.stdout).to.include("# pass 1"); + }); +}); diff --git a/integration_test/run-locally.sh b/integration_test/run-locally.sh new file mode 100644 index 0000000..2eb0fe7 --- /dev/null +++ b/integration_test/run-locally.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +IMAGE_VERSION=2.3.2 +ROOT_DIR=`cd $(dirname $0)/.. && pwd` + +docker run --rm -it \ + -v ${ROOT_DIR}:/root/src \ + givery/track-mysql:${IMAGE_VERSION} \ + mocha integration_test/mysql.test.js diff --git a/integration_test/util.js b/integration_test/util.js new file mode 100644 index 0000000..7e85682 --- /dev/null +++ b/integration_test/util.js @@ -0,0 +1,49 @@ +const fs = require("fs"); +const cp = require("child_process"); +const util = require("util"); + +async function write(dir, files) { + await fs.promises.mkdir(dir, { recursive: true }); + for (const [path, content] of Object.entries(files)) { + if (typeof content === "string") { + await fs.promises.writeFile(`${dir}/${path}`, content, "utf-8"); + } else { + await write(`${dir}/${path}`, content); + } + } +} + +function trimTextBlock(text) { + const lines = text.split("\n"); + const firstLine = lines.findIndex(s => s.trim().length > 0); + const indent = (/^\s*/.exec(lines[firstLine])[0] || { length: 0 }).length; + return lines.slice(firstLine).map(s => s.substring(indent)).join("\n"); +} + +async function exec(command, options) { + try { + const { stdout, stderr } = await util.promisify(cp.exec)(command, options); + // stdout && console.log(stdout); + // stderr && console.error(stderr); + return { + ok: true, + stdout, + stderr, + }; + } catch (err) { + // err.stdout && console.error(err.stdout); + // err.stderr && console.error(err.stderr); + return { + ok: false, + stdout: err.stdout, + stderr: err.stderr, + ...err, + }; + } +} + +module.exports = { + write, + trimTextBlock, + exec, +} diff --git a/package-lock.json b/package-lock.json index 669a296..f000995 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,6 +35,7 @@ "node": ">=16" }, "peerDependencies": { + "mysql": "2.18", "sqlite3": "^5.0.11" } }, @@ -396,6 +397,15 @@ } ] }, + "node_modules/bignumber.js": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", + "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==", + "peer": true, + "engines": { + "node": "*" + } + }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", @@ -751,6 +761,12 @@ "node": ">= 10.13.0" } }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "peer": true + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -2374,6 +2390,12 @@ "node": ">=0.10.0" } }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "peer": true + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -2897,6 +2919,36 @@ "node": ">= 10.13.0" } }, + "node_modules/mysql": { + "version": "2.18.1", + "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz", + "integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==", + "peer": true, + "dependencies": { + "bignumber.js": "9.0.0", + "readable-stream": "2.3.7", + "safe-buffer": "5.1.2", + "sqlstring": "2.3.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mysql/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "peer": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, "node_modules/napi-build-utils": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", @@ -3445,6 +3497,12 @@ "node": ">=10" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "peer": true + }, "node_modules/promise": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", @@ -3930,6 +3988,15 @@ } } }, + "node_modules/sqlstring": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", + "integrity": "sha512-ooAzh/7dxIG5+uDik1z/Rd1vli0+38izZhGzSa34FwR7IbelPWCCKSNIl8jlL/F7ERvy8CB2jNeM1E9i9mXMAQ==", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/ssri": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", diff --git a/package.json b/package.json index de7c082..fda2fba 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,8 @@ "description": "Test utility for Track database challenges", "main": "index.js", "scripts": { - "test": "gulp" + "test": "gulp", + "integration_test": "mocha integration_test" }, "bin": { "track-db": "bin/track-db.js", @@ -32,7 +33,8 @@ "yaml": "^1.6.0" }, "peerDependencies": { - "sqlite3": "^5.0.11" + "sqlite3": "^5.0.11", + "mysql": "2.18" }, "devDependencies": { "chai": "^4.2.0",