diff --git a/.kokoro/build.sh b/.kokoro/build.sh index babf4a6f23..4bc7ede40d 100755 --- a/.kokoro/build.sh +++ b/.kokoro/build.sh @@ -32,11 +32,11 @@ export DB_NAME="kokoro_ci" export DB_USER="kokoro_ci" export DB_PASS=$(cat $KOKORO_GFILE_DIR/secrets-sql-password.txt) if [[ $SQL_CLIENT == 'pg' ]]; then - export CONNECTION_NAME=$(cat $KOKORO_GFILE_DIR/secrets-pg-connection-name.txt) + export INSTANCE_CONNECTION_NAME=$(cat $KOKORO_GFILE_DIR/secrets-pg-connection-name.txt) elif [[ $SQL_CLIENT == 'sqlserver' ]]; then - export CONNECTION_NAME=$(cat $KOKORO_GFILE_DIR/secrets-sqlserver-connection-name.txt) + export INSTANCE_CONNECTION_NAME=$(cat $KOKORO_GFILE_DIR/secrets-sqlserver-connection-name.txt) elif [[ $SQL_CLIENT == 'mysql' ]]; then - export CONNECTION_NAME=$(cat $KOKORO_GFILE_DIR/secrets-mysql-connection-name.txt) + export INSTANCE_CONNECTION_NAME=$(cat $KOKORO_GFILE_DIR/secrets-mysql-connection-name.txt) fi @@ -99,10 +99,13 @@ if [[ $SQL_CLIENT ]]; then wget --quiet https://dl.google.com/cloudsql/cloud_sql_proxy.linux.amd64 -O cloud_sql_proxy chmod +x cloud_sql_proxy if [[ $SQL_CLIENT == 'sqlserver' ]]; then - ./cloud_sql_proxy -instances="${CONNECTION_NAME}"=tcp:1433 &>> cloud_sql_proxy.log & + ./cloud_sql_proxy -instances="${INSTANCE_CONNECTION_NAME}"=tcp:1433 &>> cloud_sql_proxy.log & + elif [[ $SQL_CLIENT == 'mysql' ]]; then + export DB_HOST=127.0.0.1:3306 + ./cloud_sql_proxy -instances="${INSTANCE_CONNECTION_NAME}"=tcp:3306 &>> cloud_sql_proxy.log & else - mkdir /cloudsql; chmod 777 /cloudsql - ./cloud_sql_proxy -dir=/cloudsql -instances="${CONNECTION_NAME}" &>> cloud_sql_proxy.log & + export DB_HOST=127.0.0.1:5432 + ./cloud_sql_proxy -instances="${INSTANCE_CONNECTION_NAME}"=tcp:5432 &>> cloud_sql_proxy.log & fi fi diff --git a/cloud-sql/mysql/mysql/README.md b/cloud-sql/mysql/mysql/README.md index e9fc54ba52..cd41543629 100644 --- a/cloud-sql/mysql/mysql/README.md +++ b/cloud-sql/mysql/mysql/README.md @@ -34,15 +34,76 @@ secure solution such as [Cloud KMS](https://cloud.google.com/kms/) to help keep To run this application locally, download and install the `cloud_sql_proxy` by [following the instructions](https://cloud.google.com/sql/docs/mysql/sql-proxy#install). -Once the proxy is ready, use the following command to start the proxy in the -background: +Instructions are provided below for using the proxy with a TCP connection or a Unix Domain Socket. +On Linux or Mac OS you can use either option, but on Windows the proxy currently requires a TCP +connection. + +### Launch proxy with TCP + +To run the sample locally with a TCP connection, set environment variables and launch the proxy as +shown below. + +#### Linux / Mac OS +Use these terminal commands to initialize environment variables: +```bash +export GOOGLE_APPLICATION_CREDENTIALS=/path/to/service/account/key.json +export DB_HOST='127.0.0.1:3306' +export DB_USER='' +export DB_PASS='' +export DB_NAME='' +``` + +Then use this command to launch the proxy in the background: +```bash +./cloud_sql_proxy -instances=::=tcp:3306 -credential_file=$GOOGLE_APPLICATION_CREDENTIALS & +``` + +#### Windows/PowerShell +Use these PowerShell commands to initialize environment variables: +```powershell +$env:GOOGLE_APPLICATION_CREDENTIALS="" +$env:DB_HOST="127.0.0.1:3306" +$env:DB_USER="" +$env:DB_PASS="" +$env:DB_NAME="" +``` + +Then use this command to launch the proxy in a separate PowerShell session: +```powershell +Start-Process -filepath "C:\" -ArgumentList "-instances=::=tcp:3306 -credential_file=" +``` + +### Launch proxy with Unix Domain Socket +NOTE: this option is currently only supported on Linux and Mac OS. Windows users should use the +[Launch proxy with TCP](#launch-proxy-with-tcp) option. + +To use a Unix socket, you'll need to create a directory and give write access to the user running +the proxy. For example: +```bash +sudo mkdir /path/to/the/new/directory +sudo chown -R $USER /path/to/the/new/directory +``` +You'll also need to initialize an environment variable containing the directory you just created: +```bash +export DB_SOCKET_PATH=/path/to/the/new/directory +``` + +Use these terminal commands to initialize other environment variables as well: +```bash +export GOOGLE_APPLICATION_CREDENTIALS=/path/to/service/account/key.json +export INSTANCE_CONNECTION_NAME='::' +export DB_USER='' +export DB_PASS='' +export DB_NAME='' +``` + +Then use this command to launch the proxy in the background: + ```bash -./cloud_sql_proxy -dir=/cloudsql --instances=$CLOUD_SQL_CONNECTION_NAME --credential_file=$GOOGLE_APPLICATION_CREDENTIALS +./cloud_sql_proxy -dir=$DB_SOCKET_PATH --instances=$INSTANCE_CONNECTION_NAME --credential_file=$GOOGLE_APPLICATION_CREDENTIALS & ``` -Note: Make sure to run the command under a user with write access in the -`/cloudsql` directory. This proxy will use this folder to create a unix socket -the application will use to connect to Cloud SQL. +### Testing the application Next, setup install the requirements with `npm`: ```bash npm install diff --git a/cloud-sql/mysql/mysql/app.flexible.yaml b/cloud-sql/mysql/mysql/app.flexible.yaml index 22c02166cb..16646a37ec 100644 --- a/cloud-sql/mysql/mysql/app.flexible.yaml +++ b/cloud-sql/mysql/mysql/app.flexible.yaml @@ -21,7 +21,7 @@ env_variables: DB_PASS: MY_DB_PASSWORD DB_NAME: MY_DATABASE # e.g. my-awesome-project:us-central1:my-cloud-sql-instance - CLOUD_SQL_CONNECTION_NAME: :: + INSTANCE_CONNECTION_NAME: :: beta_settings: # The connection name of your instance, available by using diff --git a/cloud-sql/mysql/mysql/app.standard.yaml b/cloud-sql/mysql/mysql/app.standard.yaml index 8103e36f58..998e98080e 100644 --- a/cloud-sql/mysql/mysql/app.standard.yaml +++ b/cloud-sql/mysql/mysql/app.standard.yaml @@ -20,4 +20,4 @@ env_variables: DB_PASS: MY_DB_PASSWORD DB_NAME: MY_DATABASE # e.g. my-awesome-project:us-central1:my-cloud-sql-instance - CLOUD_SQL_CONNECTION_NAME: :: + INSTANCE_CONNECTION_NAME: :: diff --git a/cloud-sql/mysql/mysql/server.js b/cloud-sql/mysql/mysql/server.js index d0eedcbd2d..65ebbcf8b2 100644 --- a/cloud-sql/mysql/mysql/server.js +++ b/cloud-sql/mysql/mysql/server.js @@ -41,20 +41,43 @@ const logger = winston.createLogger({ transports: [new winston.transports.Console(), loggingWinston], }); -// [START cloud_sql_mysql_mysql_create] -const createPool = async () => { +// [START cloud_sql_mysql_mysql_create_tcp] +const createTcpPool = async (config) => { + // Extract host and port from socket address + const dbSocketAddr = process.env.DB_HOST.split(":") + + // Establish a connection to the database return await mysql.createPool({ user: process.env.DB_USER, // e.g. 'my-db-user' password: process.env.DB_PASS, // e.g. 'my-db-password' database: process.env.DB_NAME, // e.g. 'my-database' - // If connecting via unix domain socket, specify the path - socketPath: `/cloudsql/${process.env.CLOUD_SQL_CONNECTION_NAME}`, - // If connecting via TCP, enter the IP and port instead - // host: 'localhost', - // port: 3306, + host: dbSocketAddr[0], // e.g. '127.0.0.1' + port: dbSocketAddr[1], // e.g. '3306' + // ... Specify additional properties here. + ...config + }); +} +// [END cloud_sql_mysql_mysql_create_tcp] - //[START_EXCLUDE] +// [START cloud_sql_mysql_mysql_create_socket] +const createUnixSocketPool = async (config) => { + const dbSocketPath = process.env.DB_SOCKET_PATH || "/cloudsql" + + // Establish a connection to the database + return await mysql.createPool({ + user: process.env.DB_USER, // e.g. 'my-db-user' + password: process.env.DB_PASS, // e.g. 'my-db-password' + database: process.env.DB_NAME, // e.g. 'my-database' + // If connecting via unix domain socket, specify the path + socketPath: `${dbSocketPath}/${process.env.INSTANCE_CONNECTION_NAME}`, + // Specify additional properties here. + ...config + }); +} +// [END cloud_sql_mysql_mysql_create_socket] +const createPool = async () => { + const config = { // [START cloud_sql_mysql_mysql_limit] // 'connectionLimit' is the maximum number of connections the pool is allowed // to keep at once. @@ -81,9 +104,13 @@ const createPool = async () => { // The mysql module automatically uses exponential delays between failed // connection attempts. // [END cloud_sql_mysql_mysql_backoff] - - //[END_EXCLUDE] - }); + } + if (process.env.DB_HOST) { + return await createTcpPool(config); + } else { + return await createUnixSocketPool(config); + } + }; // [END cloud_sql_mysql_mysql_create] diff --git a/cloud-sql/mysql/mysql/test/server.test.js b/cloud-sql/mysql/mysql/test/server.test.js index 0c202016d8..485bc5acc6 100644 --- a/cloud-sql/mysql/mysql/test/server.test.js +++ b/cloud-sql/mysql/mysql/test/server.test.js @@ -14,25 +14,35 @@ 'use strict'; +const path = require('path'); const request = require('supertest'); -const sinon = require('sinon'); const assert = require('assert'); -// Stub out MySQL calls -const stubMysql = sinon.stub(require('promise-mysql')); -const poolStub = sinon.stub(); -const queryStub = sinon.stub(); -queryStub.withArgs(sinon.match('SELECT COUNT(vote_id)')).resolves([{count: 1}]); -queryStub.withArgs(sinon.match('SELECT candidate, time_cast')).resolves([]); -poolStub['query'] = queryStub; -stubMysql.createPool.returns(poolStub); +const SAMPLE_PATH = path.join(__dirname, '../server.js'); -const server = require('../server.js'); +const server = require(SAMPLE_PATH); -it('check index page', async () => { - const response = await request(server).get('/').timeout(3000); +after(() => { + server.close(); +}); + +it('should display the default page', async () => { + await request(server) + .get('/') + .expect(200) + .expect((response) => { + assert.ok(response.text.includes('Tabs VS Spaces')); + }); +}); + +it('should handle insert error', async () => { + const expectedResult = 'Invalid team specified'; - assert.strictEqual(response.status, 200); + await request(server) + .post('/') + .expect(400) + .expect((response) => { + assert.ok(response.text.includes(expectedResult)); + }); }); -server.close(); diff --git a/cloud-sql/postgres/knex/README.md b/cloud-sql/postgres/knex/README.md index 37145e3dfe..4156daaecb 100644 --- a/cloud-sql/postgres/knex/README.md +++ b/cloud-sql/postgres/knex/README.md @@ -14,7 +14,7 @@ and password that you specify for the default 'postgres' user. 3. Create a database for your application by following these [instructions](https://cloud.google.com/sql/docs/postgres/create-manage-databases). Note the database name. 4. Create a service account with the 'Cloud SQL Client' permissions by following these -[instructions](https://cloud.google.com/sql/docs/mysql/connect-external-app#4_if_required_by_your_authentication_method_create_a_service_account). +[instructions](https://cloud.google.com/sql/docs/postgres/connect-external-app#4_if_required_by_your_authentication_method_create_a_service_account). Download a JSON key to use to authenticate your connection. 5. Use the information noted in the previous steps: @@ -35,14 +35,76 @@ Setting up the Cloud SQL database for the app requires setting up the app for lo 1. To run this application locally, download and install the `cloud_sql_proxy` by [following the instructions](https://cloud.google.com/sql/docs/postgres/sql-proxy#install). - Once the proxy is ready, use the following command to start the proxy in the - background: - ```bash - ./cloud_sql_proxy -dir=/cloudsql -instances=$CLOUD_SQL_CONNECTION_NAME -credential_file=$GOOGLE_APPLICATION_CREDENTIALS - ``` - Note: Make sure to run the command under a user with write access in the - `/cloudsql` directory. This proxy will use this folder to create a unix socket - the application will use to connect to Cloud SQL. +Instructions are provided below for using the proxy with a TCP connection or a Unix Domain Socket. +On Linux or Mac OS you can use either option, but on Windows the proxy currently requires a TCP +connection. + +### Launch proxy with TCP + +To run the sample locally with a TCP connection, set environment variables and launch the proxy as +shown below. + +#### Linux / Mac OS +Use these terminal commands to initialize environment variables: +```bash +export GOOGLE_APPLICATION_CREDENTIALS=/path/to/service/account/key.json +export DB_HOST='127.0.0.1:5432' +export DB_USER='' +export DB_PASS='' +export DB_NAME='' +``` + +Then use this command to launch the proxy in the background: +```bash +./cloud_sql_proxy -instances=::=tcp:5432 -credential_file=$GOOGLE_APPLICATION_CREDENTIALS & +``` + +#### Windows/PowerShell +Use these PowerShell commands to initialize environment variables: +```powershell +$env:GOOGLE_APPLICATION_CREDENTIALS="" +$env:DB_HOST="127.0.0.1:5432" +$env:DB_USER="" +$env:DB_PASS="" +$env:DB_NAME="" +``` + +Then use this command to launch the proxy in a separate PowerShell session: +```powershell +Start-Process -filepath "C:\" -ArgumentList "-instances=::=tcp:5432 -credential_file=" +``` + +### Launch proxy with Unix Domain Socket +NOTE: this option is currently only supported on Linux and Mac OS. Windows users should use the +[Launch proxy with TCP](#launch-proxy-with-tcp) option. + +To use a Unix socket, you'll need to create a directory and give write access to the user running +the proxy. For example: +```bash +sudo mkdir /path/to/the/new/directory +sudo chown -R $USER /path/to/the/new/directory +``` +You'll also need to initialize an environment variable containing the directory you just created: +```bash +export DB_SOCKET_PATH=/path/to/the/new/directory +``` + +Use these terminal commands to initialize other environment variables as well: +```bash +export GOOGLE_APPLICATION_CREDENTIALS=/path/to/service/account/key.json +export INSTANCE_CONNECTION_NAME='::' +export DB_USER='' +export DB_PASS='' +export DB_NAME='' +``` + +Then use this command to launch the proxy in the background: + +```bash +./cloud_sql_proxy -dir=$DB_SOCKET_PATH --instances=$INSTANCE_CONNECTION_NAME --credential_file=$GOOGLE_APPLICATION_CREDENTIALS & +``` + +### Testing the application 2. Next, install the Node.js packages necessary to run the app locally by running the following command: diff --git a/cloud-sql/postgres/knex/app.flexible.yaml b/cloud-sql/postgres/knex/app.flexible.yaml index 34a67953a1..d1ba84bf96 100644 --- a/cloud-sql/postgres/knex/app.flexible.yaml +++ b/cloud-sql/postgres/knex/app.flexible.yaml @@ -21,7 +21,7 @@ env_variables: DB_PASS: MY_DB_PASSWORD DB_NAME: MY_DATABASE # e.g. my-awesome-project:us-central1:my-cloud-sql-instance - CLOUD_SQL_INSTANCE_NAME: :: + INSTANCE_CONNECTION_NAME: :: beta_settings: # The connection name of your instance, available by using diff --git a/cloud-sql/postgres/knex/app.standard.yaml b/cloud-sql/postgres/knex/app.standard.yaml index 608834b32c..0c2e568b64 100644 --- a/cloud-sql/postgres/knex/app.standard.yaml +++ b/cloud-sql/postgres/knex/app.standard.yaml @@ -20,7 +20,7 @@ env_variables: DB_PASS: MY_DB_PASSWORD DB_NAME: MY_DATABASE # e.g. my-awesome-project:us-central1:my-cloud-sql-instance - CLOUD_SQL_INSTANCE_NAME: :: + INSTANCE_CONNECTION_NAME: :: beta_settings: # The connection name of your instance, available by using diff --git a/cloud-sql/postgres/knex/createTable.js b/cloud-sql/postgres/knex/createTable.js index 07aaf96ecf..5ede208e37 100644 --- a/cloud-sql/postgres/knex/createTable.js +++ b/cloud-sql/postgres/knex/createTable.js @@ -17,8 +17,17 @@ const Knex = require('knex'); const createTable = async (config) => { + const socketPath = process.env.DB_SOCKET_PATH || "/cloudsql"; + // Connect to the database - config.host = `/cloudsql/${config.connectionName}`; + if (config.dbHost){ + const dbSocketAddr = config.dbHost.split(":"); + config.host = dbSocketAddr[0]; + config.port = dbSocketAddr[1]; + } else { + config.host = `${socketPath}/${config.connectionName}`; + } + const knex = Knex({client: 'pg', connection: config}); // Create the "votes" table @@ -41,7 +50,7 @@ const createTable = async (config) => { require('yargs') .command( - '* ', + '* [dbHost]', 'Create a "votes" table', {}, createTable diff --git a/cloud-sql/postgres/knex/server.js b/cloud-sql/postgres/knex/server.js index 78f1def34c..8d0ff32db2 100644 --- a/cloud-sql/postgres/knex/server.js +++ b/cloud-sql/postgres/knex/server.js @@ -44,36 +44,60 @@ const logger = winston.createLogger({ transports: [new winston.transports.Console(), loggingWinston], }); -// [START cloud_sql_postgres_knex_create] -// Initialize Knex, a Node.js SQL query builder library with built-in connection pooling. -const connect = () => { - // Configure which instance and what database user to connect with. - // Remember - storing secrets in plaintext is potentially unsafe. Consider using - // something like https://cloud.google.com/kms/ to help keep secrets secret. - const config = { - user: process.env.DB_USER, // e.g. 'my-user' - password: process.env.DB_PASS, // e.g. 'my-user-password' - database: process.env.DB_NAME, // e.g. 'my-database' - }; +// [START cloud_sql_postgres_knex_create_tcp] +const connectWithTcp = (config) => { + // Extract host and port from socket address + const dbSocketAddr = process.env.DB_HOST.split(":") // e.g. '127.0.0.1:5432' + + // Establish a connection to the database + return Knex({ + client: 'pg', + connection: { + user: process.env.DB_USER, // e.g. 'my-user' + password: process.env.DB_PASS, // e.g. 'my-user-password' + database: process.env.DB_NAME, // e.g. 'my-database' + host: dbSocketAddr[0], // e.g. '127.0.0.1' + port: dbSocketAddr[1], // e.g. '5432' + }, + // ... Specify additional properties here. + ...config + }); +} +// [END cloud_sql_postgres_knex_create_tcp] - config.host = `/cloudsql/${process.env.CLOUD_SQL_CONNECTION_NAME}`; +// [START cloud_sql_postgres_knex_create_socket] +const connectWithUnixSockets = (config) => { + const dbSocketPath = process.env.DB_SOCKET_PATH || "/cloudsql" // Establish a connection to the database - const knex = Knex({ + return Knex({ client: 'pg', - connection: config, + connection: { + user: process.env.DB_USER, // e.g. 'my-user' + password: process.env.DB_PASS, // e.g. 'my-user-password' + database: process.env.DB_NAME, // e.g. 'my-database' + host: `${dbSocketPath}/${process.env.INSTANCE_CONNECTION_NAME}`, + }, + // ... Specify additional properties here. + ...config }); +} +// [END cloud_sql_postgres_knex_create_socket] - // ... Specify additional properties here. - // [START_EXCLUDE] +// Initialize Knex, a Node.js SQL query builder library with built-in connection pooling. +const connect = () => { + // Configure which instance and what database user to connect with. + // Remember - storing secrets in plaintext is potentially unsafe. Consider using + // something like https://cloud.google.com/kms/ to help keep secrets secret. + let config = {pool: {}}; // [START cloud_sql_postgres_knex_limit] // 'max' limits the total number of concurrent connections this pool will keep. Ideal // values for this setting are highly variable on app design, infrastructure, and database. - knex.client.pool.max = 5; + config.pool.max = 5; // 'min' is the minimum number of idle connections Knex maintains in the pool. // Additional connections will be established to meet this value unless the pool is full. - knex.client.pool.min = 5; + config.pool.min = 5; // [END cloud_sql_postgres_knex_limit] // [START cloud_sql_postgres_knex_timeout] @@ -81,28 +105,32 @@ const connect = () => { // connection from the pool. This is slightly different from connectionTimeout, because acquiring // a pool connection does not always involve making a new connection, and may include multiple retries. // when making a connection - knex.client.pool.acquireTimeoutMillis = 60000; // 60 seconds + config.pool.acquireTimeoutMillis = 60000; // 60 seconds // 'createTimeoutMillis` is the maximum number of milliseconds to wait trying to establish an // initial connection before retrying. // After acquireTimeoutMillis has passed, a timeout exception will be thrown. - knex.client.pool.createTimeoutMillis = 30000; // 30 seconds + config.createTimeoutMillis = 30000; // 30 seconds // 'idleTimeoutMillis' is the number of milliseconds a connection must sit idle in the pool // and not be checked out before it is automatically closed. - knex.client.pool.idleTimeoutMillis = 600000; // 10 minutes + config.idleTimeoutMillis = 600000; // 10 minutes // [END cloud_sql_postgres_knex_timeout] // [START cloud_sql_postgres_knex_backoff] // 'knex' uses a built-in retry strategy which does not implement backoff. // 'createRetryIntervalMillis' is how long to idle after failed connection creation before trying again - knex.client.pool.createRetryIntervalMillis = 200; // 0.2 seconds + config.createRetryIntervalMillis = 200; // 0.2 seconds // [END cloud_sql_postgres_knex_backoff] - // [END_EXCLUDE] + let knex; + if (process.env.DB_HOST) { + knex = connectWithTcp(config); + } else { + knex = connectWithUnixSockets(config); + } return knex; }; const knex = connect(); -// [END cloud_sql_postgres_knex_create] // [START cloud_sql_postgres_knex_connection] /** diff --git a/cloud-sql/postgres/knex/test/createTable.test.js b/cloud-sql/postgres/knex/test/createTable.test.js index a02aa67f31..06b3d5e551 100644 --- a/cloud-sql/postgres/knex/test/createTable.test.js +++ b/cloud-sql/postgres/knex/test/createTable.test.js @@ -21,19 +21,28 @@ const {exec} = require('child_process'); const cwd = path.join(__dirname, '..'); -const {DB_USER, DB_PASS, DB_NAME} = process.env; -const CONNECTION_NAME = process.env.CLOUD_SQL_CONNECTION_NAME; +const {DB_USER, DB_PASS, DB_NAME, CONNECTION_NAME, DB_HOST} = process.env; +const SOCKET_PATH = process.env.DB_SOCKET_PATH || "/cloudsql" before(async () => { + const connection = { + user: DB_USER, + password: DB_PASS, + database: DB_NAME, + }; + + if (DB_HOST) { + const dbSocketAddr = process.env.DB_HOST.split(":"); + connection.host = dbSocketAddr[0]; + connection.port = dbSocketAddr[1]; + } else { + connection.host = `${SOCKET_PATH}/${CONNECTION_NAME}`; + } + try { const knex = Knex({ client: 'pg', - connection: { - user: DB_USER, - password: DB_PASS, - database: DB_NAME, - host: `/cloudsql/${CONNECTION_NAME}`, - }, + connection, }); await knex.schema.dropTable('votes'); } catch (err) { @@ -43,7 +52,7 @@ before(async () => { it('should create a table', (done) => { exec( - `node createTable.js ${DB_USER} ${DB_PASS} ${DB_NAME} ${CONNECTION_NAME}`, + `node createTable.js ${DB_USER} ${DB_PASS} ${DB_NAME} ${CONNECTION_NAME} ${DB_HOST}`, {cwd}, (err, stdout) => { assert.ok(stdout.includes(`Successfully created 'votes' table.`)); @@ -54,7 +63,7 @@ it('should create a table', (done) => { it('should handle existing tables', (done) => { exec( - `node createTable.js ${DB_USER} ${DB_PASS} ${DB_NAME} ${CONNECTION_NAME}`, + `node createTable.js ${DB_USER} ${DB_PASS} ${DB_NAME} ${CONNECTION_NAME} ${DB_HOST}`, {cwd}, (err, stdout, stderr) => { assert.ok(stderr.includes("Failed to create 'votes' table:"));