From 128282d74c484e325d4c36258f17a63a6f59e2da Mon Sep 17 00:00:00 2001
From: Lucendio <dev@lucend.io>
Date: Thu, 14 May 2020 02:43:10 +0200
Subject: [PATCH] Add make target to start db and app in a transparent way

* adjust mongoose configuration
* documents more make targets in readme
* applied npm scripts convention of the client to the corresponding
  server scripts in order to be more consistent (`start` is now meant
  for local development)
---
 Makefile                                 | 53 ++++++++++++++++++++----
 README.md                                | 42 +++++++++++++++----
 app/server/package.json                  |  6 +--
 app/server/src/db/mongo.js               |  9 ++--
 stack/{mongod.conf => local.mongod.conf} |  0
 5 files changed, 85 insertions(+), 25 deletions(-)
 rename stack/{mongod.conf => local.mongod.conf} (100%)

diff --git a/Makefile b/Makefile
index 8cc33f1..fa1fe06 100644
--- a/Makefile
+++ b/Makefile
@@ -47,6 +47,10 @@ MONGODB_SHA256 ?= $(shell cat $(STACK_DIR)/versions/mongodb.256.sums | grep $(PL
 
 
 
+SERVER_PUBLIC_URL ?= http://localhost:3000
+CLIENT_BUILD_PATH ?= $(MKFILE_DIR)/app/server/src/public
+
+
 
 
 default: all
@@ -66,28 +70,32 @@ install-deps: $(APP_NODE_MODULE_DIRS)
 run-db: export PATH := $(BIN_DIR):$(PATH)
 run-db: | $(LOG_DIR)/ $(DATA_DIR)/
 	mkdir -p $(DATA_DIR)/db
-	mongod --config $(STACK_DIR)/mongod.conf
+	mongod --config $(STACK_DIR)/local.mongod.conf
 
 
 .PHONY: run-local
 run-local: export PATH := $(BIN_DIR):$(PATH)
-run-local:
+run-local: build
 	cd $(MKFILE_DIR)/app/server \
-	&& npm run dev
+	&& npm start
 
 
 .PHONY: test
 test: export PATH := $(BIN_DIR):$(PATH)
+test: randomString = $(shell LC_ALL=C tr -dc 'a-zA-Z0-9' < /dev/urandom | fold -w 32 | head -n 1)
 test:
 	cd $(MKFILE_DIR)/app/client \
 	&& npm run test
 	cd $(MKFILE_DIR)/app/server \
+	PORT=3002 \
+    MONGODB_URL=mongodb://localhost:27017/$(randomString) \
+    JWT_SECRET=$(randomString) \
 	&& npm run test
 
 
-.PHONY: test-local
-test-local: export PATH := $(BIN_DIR):$(PATH)
-test-local:
+.PHONY: test-client-local
+test-client-local: export PATH := $(BIN_DIR):$(PATH)
+test-client-local:
 	cd $(MKFILE_DIR)/app/client \
 	&& npm run test:dev
 
@@ -95,10 +103,11 @@ test-local:
 .PHONY: build
 build: export PATH := $(BIN_DIR):$(PATH)
 build:
+	rm -rf $(CLIENT_BUILD_PATH)
 	cd $(MKFILE_DIR)/app/client \
-	&& rm -rf ./build \
-	&& PUBLIC_URL=http://localhost:3000 \
-	npm run build
+	&& PUBLIC_URL=$(SERVER_PUBLIC_URL) \
+		BUILD_PATH=$(CLIENT_BUILD_PATH) \
+		node ./scripts/build.js
 
 
 
@@ -108,6 +117,32 @@ clean: clean-stack clean-modules
 
 
 
+.PHONY: start
+start: export PATH := $(BIN_DIR):$(PATH)
+start: SERVER_PUBLIC_URL = http://localhost:3001
+start: build
+start: | $(DATA_DIR)/ $(LOG_DIR)/
+	mkdir -p $(DATA_DIR)/db
+
+	(exec mongod \
+		--port 27017 \
+		--bind_ip localhost \
+		--logpath /dev/stdout \
+		--dbpath $(DATA_DIR)/db \
+	) & PIDS[1]=$$!; \
+	\
+	(PORT=3001 \
+	MONGODB_URL=mongodb://localhost:27017/todo-app \
+	JWT_SECRET=myjwtsecret \
+	exec node $(MKFILE_DIR)/app/server/src/index.js \
+	) & PIDS[2]=$$!; \
+	\
+	for PID in $${PIDS[*]}; do wait $${PID}; done;
+
+
+
+
+
 $(LOCAL_DIR)/%/:
 	mkdir -p $(@)
 
diff --git a/README.md b/README.md
index ef0ee31..6753546 100644
--- a/README.md
+++ b/README.md
@@ -13,10 +13,16 @@ For more information regarding the app, please have a look into its [README](./a
 The `Makefile` is the main entry point for this repository. It's meant to be used for documentation purposes and local
 development/invocation only. The following commands are available:
 
+*NOTE:*
+
+The `Makefile` is solely meant to showcase how to interact with the application and the code base, it is not recommended
+to invoke make targets from the CI/CD, but rather use automation-specific interfaces (e.g. `Jenkinsfile`, `.travis.yml`,
+etc.), which would then invoke logic also shown under some make target. 
+
 
 #### `make install-stack`
 
-* install technology stack (nodejs, npm, mongodb) locally within the project
+* install technology stack (Nodejs, npm, MongoDB) as prebuild binaries locally within the project
 * in order for the application-related targets to pick up these binaries, the `PATH` variable is adjusted and exported
   for the corresponding target
 
@@ -38,22 +44,40 @@ development/invocation only. The following commands are available:
 
 #### `make run-local`
 
+*NOTE: it might be desired to start a database first (e.g. `make run-db`)*
+
+* build client 
 * start server with development configuration
-* file watcher enabled
 
 
-#### `make test-local`
+#### `make test`
+
+*NOTE: requires MongoDB to be running (e.g. `make run-db`)*
+
+* run client tests in [CI mode](https://jestjs.io/docs/en/cli.html#--ci) (exits regardless of the test outcome; closed tty)
+* run server tests in [CI mode](https://jestjs.io/docs/en/cli.html#--ci) (exits regardless of the test outcome; closed tty)
+
+
+#### `make test-client-local`
 
 * run client tests
 
 
-#### `make test`
+#### `make build`
 
-* run client tests in [CI mode](https://jestjs.io/docs/en/cli.html#--ci) (exits regardless of the test outcome; closed tty)
-* run server tests in [CI mode](https://jestjs.io/docs/en/cli.html#--ci) (exits regardless of the test outcome; closed tty)
+* build client
+
+
+#### `make clean`
+
+* removes all dependencies that were installed locally 
+    * node, npm, mongo
+    * npm modules for server and client
 
 
-### Notes
+#### `make start`
 
-* the `Makefile` shows how to interact with the code base, it is not recommended to invoke make targets from the CI/CD,
-but rather use automation-specific interfaces (e.g. `Jenkinsfile`, `.travis.yml`, etc.). 
+* start a MongoDB process with an explicit inline-configuration
+* start the application process with variables being set only visible to that invocation (as an alternative to the
+  environment configuration file `app/server/dev.env`)
+* block terminal to keep it as the output medium. To stop again, send a termination signal via `Ctrl+C`
diff --git a/app/server/package.json b/app/server/package.json
index 60b66d9..cf50f73 100644
--- a/app/server/package.json
+++ b/app/server/package.json
@@ -4,9 +4,9 @@
   "main": "index.js",
   "license": "MIT",
   "scripts": {
-    "start": "node src/index",
-    "dev": "env-cmd -f ./dev.env nodemon src/index",
-    "test": "env-cmd -f ./dev.env jest --ci"
+    "start": "env-cmd -f ./dev.env nodemon src/index.js",
+    "test": "jest --ci",
+    "test:dev": "env-cmd -f ./dev.env jest"
   },
   "devDependencies": {
     "@shelf/jest-mongodb": "^1.1.5",
diff --git a/app/server/src/db/mongo.js b/app/server/src/db/mongo.js
index 16c5284..36ad77d 100644
--- a/app/server/src/db/mongo.js
+++ b/app/server/src/db/mongo.js
@@ -7,12 +7,13 @@ const mongooseInstance_ = mongoose.connect(
         useNewUrlParser: true,
         useCreateIndex: true,
         useFindAndModify: false,
-        useUnifiedTopology: true,
 
-        // NOTE: as of the docs `connectTimeoutMS` should be used when `useUnifiedTopology: true`,
-        // but apparently it has no impact what so ever. Instead, the following works ¯\_(ツ)_/¯
-        serverSelectionTimeoutMS: 10000  // 10 sec
+        useUnifiedTopology: true,
+        heartbeatFrequencyMS: 1000 * 5,         // 1 sec * 5
+        serverSelectionTimeoutMS: 1000 * 10     // 1 sec * 10
     },
+    // TODO: make use of the event emitter to indicate each retry in logs & to increase
+    //       the overall timeout to 10 min (see https://mongoosejs.com/docs/connections.html#connection-events)
     function( err ){
         if( typeof err !== 'undefined' && err !== null ){
             console.error( new Error( `Cannot connect to database: ${ process.env.MONGODB_URL }` ) );
diff --git a/stack/mongod.conf b/stack/local.mongod.conf
similarity index 100%
rename from stack/mongod.conf
rename to stack/local.mongod.conf
-- 
GitLab