<p>I have developed a nodejs REST API, for which i have built a docker image and now deploying it as a pod on my kubernetes cluster.</p>

<p>Dockerfile</p>

<pre><code>FROM mhart/alpine-node:8
WORKDIR /home/appHome/
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD [ "npm", "start" ]
</code></pre>

<p>however, i am passing npm start as my container start up command.</p>

<p>but how do i test my node js application with npm test and verify test results?</p>

<p>when i was doing it in my local system i used to run application in backend and used to run </p>

<pre><code>npm test
</code></pre>

<p>in another window.
how to achieve the same while deploying it on kubernetes cluster! and remove the test part once it is successfull!</p>

<p>below is my script of package.json,</p>

<pre><code>"scripts": {
"test": "mocha ./test/scheduledTaskTest.js",
"start": "nodemon app.js --exec babel-node --presets es2015,stage-2",
"cmd": "set NODE_ENV=devConfig&amp;&amp; npm start"
},
</code></pre>

<p>Below are the deployment and job yaml files.</p>

<p>Deployment.yaml</p>

<pre><code>apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: scheduled-task-test
spec:
  replicas: 1
  selector:
    matchLabels:
      app: scheduled-task-test
  template:
    metadata:
      labels:
        app: scheduled-task-test
    spec:     # pod spec       
      containers:
      - name: st-c1
        image: 104466/st
        imagePullPolicy: Always
        env: 
        - name: NODE_ENV
          value: devConfig
      - name: st-c2
        image: 104466/st
        imagePullPolicy: Always
        command: [ 'sh','-c','npm test &amp;&amp; sleep 3600']'
</code></pre>

<p>TestJob.yaml</p>

<pre><code>apiVersion: batch/v1
kind: Job
metadata:
  name: scheduled-task-test-job
  labels:
    purpose: test
spec:
  template:
    spec:
      containers:
      - name: st-c1
        image: 104466/st
        imagePullPolicy: Always
        env: 
        - name: NODE_ENV
          value: devConfig
      - name: st-c2
        image: 104466/st
        imagePullPolicy: Always
        command: [ 'sh','-c','npm test &amp;&amp; sleep 3600']
      restartPolicy: Never
</code></pre>

<p>Pod status </p>

<pre><code>scheduled-task-test-7d86c87d44-q9zdv                              2/2       Running   1          8m        100.96.9.87   ip-172-20-34-139.us-west-2.compute.internal
scheduled-task-test-job-gt9hx                                     1/2       Error     0          7m        100.96.9.88   ip-172-20-34-139.us-west-2.compute.internal
</code></pre>

<p>Successfully executed test case pod log (deployment results)</p>

<pre><code>kubectl logs scheduled-task-test-7d86c87d44-q9zdv -c st-c2

&gt; ScheduledTask@1.0.0 test /home/appHome/ScheduledTask
&gt; mocha ./test/scheduledTaskTest.js



  Testing listTask api
    ✓ List all the Tasks (435ms)

  Testing addTask api
    ✓  Add a new task  (438ms)

  Testing updateTask api
    ✓  Update task

  Testing delete task api
    ✓  Delete task  (434ms)


  4 passing (1s)
</code></pre>

<p>Test failed logs, (Executed containers as in job)</p>

<pre><code>kubectl logs scheduled-task-test-job-gt9hx -c st-c2

&gt; ScheduledTask@1.0.0 test /home/appHome/ScheduledTask
&gt; mocha ./test/scheduledTaskTest.js



  Testing listTask api
    1) List all the Tasks

  Testing addTask api
    2)  Add a new task

  Testing updateTask api
    3)  Update task

  Testing delete task api
    4)  Delete task


  0 passing (61ms)
  4 failing

  1) Testing listTask api
       List all the Tasks:
     Uncaught TypeError: Cannot read property 'body' of undefined
      at Request._callback (test/scheduledTaskTest.js:24:29)
      at self.callback (node_modules/request/request.js:186:22)
      at Request.onRequestError (node_modules/request/request.js:878:8)
      at Socket.socketErrorListener (_http_client.js:387:9)
      at emitErrorNT (internal/streams/destroy.js:64:8)
      at _combinedTickCallback (internal/process/next_tick.js:138:11)
      at process._tickCallback (internal/process/next_tick.js:180:9)

  2) Testing addTask api
        Add a new task :
     Uncaught TypeError: Cannot read property 'body' of undefined
      at Request._callback (test/scheduledTaskTest.js:43:20)
      at self.callback (node_modules/request/request.js:186:22)
      at Request.onRequestError (node_modules/request/request.js:878:8)
      at Socket.socketErrorListener (_http_client.js:387:9)
      at emitErrorNT (internal/streams/destroy.js:64:8)
      at _combinedTickCallback (internal/process/next_tick.js:138:11)
      at process._tickCallback (internal/process/next_tick.js:180:9)

  3) Testing updateTask api
        Update task :
     Uncaught TypeError: Cannot read property 'body' of undefined
      at Request._callback (test/scheduledTaskTest.js:63:20)
      at self.callback (node_modules/request/request.js:186:22)
      at Request.onRequestError (node_modules/request/request.js:878:8)
      at Socket.socketErrorListener (_http_client.js:387:9)
      at emitErrorNT (internal/streams/destroy.js:64:8)
      at _combinedTickCallback (internal/process/next_tick.js:138:11)
      at process._tickCallback (internal/process/next_tick.js:180:9)

  4) Testing delete task api
        Delete task :
     Uncaught TypeError: Cannot read property 'body' of undefined
      at Request._callback (test/scheduledTaskTest.js:83:20)
      at self.callback (node_modules/request/request.js:186:22)
      at Request.onRequestError (node_modules/request/request.js:878:8)
      at Socket.socketErrorListener (_http_client.js:387:9)
      at emitErrorNT (internal/streams/destroy.js:64:8)
      at _combinedTickCallback (internal/process/next_tick.js:138:11)
      at process._tickCallback (internal/process/next_tick.js:180:9)



npm ERR! Test failed.  See above for more details.
</code></pre>

<p>Describe logs of Pod( of containers deployed as job)</p>

<pre><code>kubectl describe pod scheduled-task-test-job-gt9hx
Name:           scheduled-task-test-job-gt9hx
Namespace:      default
Node:           ip-172-20-34-139.us-west-2.compute.internal/172.20.34.139
Start Time:     Tue, 19 Jun 2018 16:28:06 +0000
Labels:         controller-uid=bf5569e5-73dd-11e8-8ede-02924b27b126
                job-name=scheduled-task-test-job
Annotations:    kubernetes.io/created-by={"kind":"SerializedReference","apiVersion":"v1","reference":{"kind":"Job","namespace":"default","name":"scheduled-task-test-job","uid":"bf5569e5-73dd-11e8-8ede-02924b27b126","...
                kubernetes.io/limit-ranger=LimitRanger plugin set: cpu request for container st-c1; cpu request for container st-c2
Status:         Running
IP:             100.96.9.88
Created By:     Job/scheduled-task-test-job
Controlled By:  Job/scheduled-task-test-job
Containers:
  st-c1:
    Container ID:   docker://7fc17e717921020cec074774ccb87956979712e7de55480be6e6bd586b28ce6d
    Image:          104466/st
    Image ID:       docker-pullable://104466/st@sha256:91414cc48e86975041c233329b1814d7c6d2b76bc839a24fa68e99f92750390f
    Port:           &lt;none&gt;
    State:          Running
      Started:      Tue, 19 Jun 2018 16:28:08 +0000
    Ready:          True
    Restart Count:  0
    Requests:
      cpu:  100m
    Environment:
      NODE_ENV:  devConfig
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-2tvsm (ro)
  st-c2:
    Container ID:  docker://95837799d34e1e14f7718acc1dc745042b94a33f115aab11a03a25ab4a569c18
    Image:         104466/st
    Image ID:      docker-pullable://104466/st@sha256:91414cc48e86975041c233329b1814d7c6d2b76bc839a24fa68e99f92750390f
    Port:          &lt;none&gt;
    Command:
      sh
      -c
      npm test &amp;&amp; sleep 3600
    State:          Terminated
      Reason:       Error
      Exit Code:    1
      Started:      Tue, 19 Jun 2018 16:28:10 +0000
      Finished:     Tue, 19 Jun 2018 16:28:12 +0000
    Ready:          False
    Restart Count:  0
    Requests:
      cpu:        100m
    Environment:  &lt;none&gt;
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-2tvsm (ro)
Conditions:
  Type           Status
  Initialized    True
  Ready          False
  PodScheduled   True
Volumes:
  default-token-2tvsm:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-2tvsm
    Optional:    false
QoS Class:       Burstable
Node-Selectors:  &lt;none&gt;
Tolerations:     node.alpha.kubernetes.io/notReady:NoExecute for 300s
                 node.alpha.kubernetes.io/unreachable:NoExecute for 300s
Events:          &lt;none&gt;
</code></pre>

<p>If you want to use Kubernetes only, then using Jobs would be the easiest way. A job creates one or more pods and ensures that a specified number of them successfully terminate. As pods successfully complete, the job tracks the successful completions. When a specified number of successful completions is reached, the job itself is complete.</p>

<p>Rough plan:</p>

<p><strong>1. Create a Job for your application.</strong><br>
You can use the Deployment of your application as a template. You need to change <code>kind: Job</code> and add <code>spec.containers.command: ["npm", "test"]</code>, the last one will replace <code>CMD [ "npm", "start" ]</code> defined in your Dockerfile. Here is an example:</p>

<pre><code>apiVersion: batch/v1
kind: Job
metadata:
  name: npm-test-job
  labels:
    purpose: test
spec:
  template:
    spec:
      containers:
      - name: npm-test-job
        image: &lt;your-image&gt;
        command: ["npm", "test"]
      restartPolicy: Never
</code></pre>

<p><strong>2. Run the Job</strong><br>
Run the Job and wait until it is complete:</p>

<pre><code>kubectl create -f npm-test-job
</code></pre>

<p><strong>3. Check the status of the Job</strong><br>
Check status of your Job, for example:</p>

<pre><code>kubectl describe jobs kubectl describe jobs | grep "Pods Statuses"
</code></pre>

<p><strong>4. Run the Deployment</strong><br>
If test finished successfully, you can start you deployment:</p>

<pre><code>kubectl create -f npm-deployment
</code></pre>

<p>Of course, you need to automate this process. Therefore, you need to develop a script implementing this logic.</p>

<hr>

<p>But my advice here: it is better to use CI tool, such as Jenkins. It integrates easily with Kubernetes and provides a vast amount of functionalities for such cases.</p>
