node.jsprometheusprometheus-pushgatewayprom-client

Node.js: Is there a way to mock the prometheus pushgateway server?


I am using node.js package prom-client to try to push different custom metrics to the Prometheus Pushgateway server.

The code is working and now I am writing the test code for the functionality. I wonder whether there is a way to mock the Prometheus Pushgateway server?

I had tried to use a normal express API server (like the following)

const express = require('express');
const bodyParser = require('body-parser');

const app = express();

let data = null;

// ROUTES FOR OUR API
// =============================================================================
const router = express.Router();

app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

router.get('/', (req, res) => {
  console.log("pushgateway server: get to '/' received");
  res.json(data);
});

router.post('/', (req, res) => {
  console.log("pushgateway server: post to '/' received");
  console.log(req.body);
  data = req.body;
  res.send('POST request to the homepage');
})

app.use(router);

// API JSON BASED ERRORS
// =============================================================================
app.use((err, req, res, next) => {
  if (req.xhr) {
    console.error(err);
    res.status(500).send({ err: 'Something failed!' });
  } else {
    next(err);
  }
});
app.use((err, req, res, next) => { // eslint-disable-line
  console.error(err);
  res.status(500).send({ err: err.message });
});

// START THE SERVER
// =============================================================================
const port = 9876;
const server = app.listen(port, '0.0.0.0');
console.log(`Prometheus Pushgateway Mock Server is listening on port ${port}`);

// SHUTDOWN HANDLING
// =============================================================================

// Nodemon Signal Handling
process.once('SIGUSR2', () => {
  console.log('Received kill signal, attempting gracefully close');
  server.close(() => {
    console.log('Closed out remaining connections');
    process.kill(process.pid, 'SIGUSR2');
  });
  setTimeout(() => {
    console.error('Timeout, forcefully shutting down');
    process.kill(process.pid, 'SIGUSR2');
  }, 3000);
});

module.exports = server;

but it did not work -- when I call gateway.pushAdd() on my test code, the server did not receive any post message.

Can anyone give me some hints on how to do this (mock the prometheus pushgateway server)?


Solution

  • So I have solved the problem by creating a simple http server.

    The following is the code of the server:

    const http = require('http');
    
    const body = [];
    let text = null;
    let path = null;
    
    function createServer(port) {
      return http.createServer()
        .on('request', (req, res) => {
          if (req.method === 'POST' || req.method === 'PUT') {
            path = req.url;
            req.on('data', (chunk) => {
              body.push(chunk);
            }).on('end', () => {
              text = Buffer.concat(body).toString();
              res.end(`${req.method} success`);
            }).on('error', (err) => {
              console.error(err);
            });
          } else if (req.method === 'GET') {
            res.end(JSON.stringify({ path, text }));
          } else if (req.method === 'DELETE') {
            path = null;
            text = null;
            res.end('DELETE success');
          }
        }).on('error', (err) => {
          console.log(`Server error: ${err}`);
        })
        .listen(port, '0.0.0.0');
    }
    
    module.exports = (createServer);
    

    The server accepts POST/PUT/DELETE/GET requests, to handle the pushAdd()/push()/delete() functions of the gateway to handle the metric data, as well as checking the push data on the mocked pushgateway.

    Also, the request.url and the text data pushed to the server are saved and passed to the test program for verification.

    The following is one of the test cases (using Mocha+Chai):

    describe('Check adding custom push count metric', () => {
      it('Check connection: should return - network status: 200, result contains custom count metric string', async () => {
        metricInstance = promMetric.createCustomPushMetric({
          name: 'test_counter',
          help: 'Used to test the pushgateway for custom counter metrics',
          type: 'counter',
          jobName: 'custom-metric-pushgateway-counter',
          groupings: { key: 'test', type: 'customMetric' },
        });
        await promMetric.addPushMetric(metricInstance, 0.879);
        await sleep(500);
        const result = await chai.request(mockPgwServer).get('/');
        expect(result).to.have.status(200);
        const json = JSON.parse(result.text);
        expect(json.path).to.equal('/metrics/job/custom-metric-pushgateway-counter/key/test/type/customMetric');
        expect(json.text).to.match(/# HELP Push_gateway_test_test_counter Used to test the pushgateway for custom counter metrics/);
        expect(json.text).to.match(/# TYPE Push_gateway_test_test_counter counter/);
        expect(json.text).to.match(/Push_gateway_test_test_counter 0.879/);
      });
    });
    

    The "path" and "text" stored in the server when the metric is posted from the client are sent back to the client when queried and verified.