github.com/web-platform-tests/wpt.fyi@v0.0.0-20240530210107-70cf978996f1/webdriver/datastore.js (about)

     1  /**
     2   * Copyright 2019 The WPT Dashboard Project. All rights reserved.
     3   * Use of this source code is governed by a BSD-style license that can be
     4   * found in the LICENSE file.
     5   */
     6  
     7  const http = require('http');
     8  const process = require('process');
     9  const { spawn } = require('child_process');
    10  
    11  const { debug } = require('debug');
    12  const log = debug('wpt.fyi');
    13  
    14  const ready = Symbol('ready');
    15  
    16  class DatastoreEmulator {
    17    /**
    18     * @typedef {object} DatastoreEmulatorConfig
    19     * @property {string} project
    20     * @property {number} port
    21     */
    22    /**
    23     * @param {DatastoreEmulatorConfig} config
    24     */
    25    constructor(config) {
    26      this.config = Object.freeze(
    27        Object.assign({
    28          project: 'test-app',
    29          port: 9091,
    30        }, config)
    31      );
    32      this.process = startDatastoreEmulator(this.config);
    33      this[ready] = this._awaitReady(this.process);
    34    }
    35  
    36    /**
    37     * @type {Promise} ready
    38     */
    39    get ready() {
    40      return this[ready];
    41    }
    42  
    43    _awaitReady(process) {
    44      return new Promise(resolve => {
    45        function retryRequest(url) {
    46          http.get(url, (res) => {
    47            if (res.statusCode == 200) {
    48              resolve();
    49            } else {
    50              retryRequest(url);
    51            }
    52          }).on('error', () => {
    53            retryRequest(url);
    54          });
    55        }
    56        retryRequest(`http://127.0.0.1:${this.config.port}`);
    57  
    58        const logDatastoreEmulator = debug('wpt.fyi:datastore');
    59        process.stderr.on('data', buffer => {
    60          logDatastoreEmulator(buffer.toString());
    61        });
    62      });
    63    }
    64  
    65    close() {
    66      return new Promise(resolve => {
    67        this.process.on('close', () => {
    68          resolve();
    69        });
    70        http.request(
    71            `http://127.0.0.1:${this.config.port}/shutdown`,
    72            {method: 'POST'}
    73            ).end();
    74      });
    75    }
    76  }
    77  
    78  /**
    79   * Launch a dev_appserver.py subprocess.
    80   *
    81   * @param {object} config
    82   * @returns DatastoreEmulator
    83   */
    84  function launch(config) {
    85    return new DatastoreEmulator(config);
    86  }
    87  
    88  function startDatastoreEmulator(config) {
    89    const child = spawn('gcloud',
    90      [
    91        'beta',
    92        'emulators',
    93        'datastore',
    94        'start',
    95        '--no-store-on-disk',
    96        '--consistency=1.0',
    97        `--project=${config.project}`,
    98        `--host-port=127.0.0.1:${config.port}`,
    99      ]);
   100    process.on('exit', () => {
   101      log('killing Datastore emulator subprocess...');
   102      child.kill();
   103    });
   104    return child;
   105  }
   106  
   107  module.exports = { DatastoreEmulator, launch };