github.com/aminovpavel/nomad@v0.11.8/ui/tests/integration/task-log-test.js (about)

     1  import { run } from '@ember/runloop';
     2  import { module, test } from 'qunit';
     3  import { setupRenderingTest } from 'ember-qunit';
     4  import { find, click, render, settled } from '@ember/test-helpers';
     5  import hbs from 'htmlbars-inline-precompile';
     6  import Pretender from 'pretender';
     7  import { logEncode } from '../../mirage/data/logs';
     8  
     9  const HOST = '1.1.1.1:1111';
    10  const allowedConnectionTime = 100;
    11  const commonProps = {
    12    interval: 200,
    13    allocation: {
    14      id: 'alloc-1',
    15      node: {
    16        httpAddr: HOST,
    17      },
    18    },
    19    task: 'task-name',
    20    clientTimeout: allowedConnectionTime,
    21    serverTimeout: allowedConnectionTime,
    22  };
    23  
    24  const logHead = [logEncode(['HEAD'], 0)];
    25  const logTail = [logEncode(['TAIL'], 0)];
    26  const streamFrames = ['one\n', 'two\n', 'three\n', 'four\n', 'five\n'];
    27  let streamPointer = 0;
    28  let logMode = null;
    29  
    30  module('Integration | Component | task log', function(hooks) {
    31    setupRenderingTest(hooks);
    32  
    33    hooks.beforeEach(function() {
    34      const handler = ({ queryParams }) => {
    35        let frames;
    36        let data;
    37  
    38        if (logMode === 'head') {
    39          frames = logHead;
    40        } else if (logMode === 'tail') {
    41          frames = logTail;
    42        } else {
    43          frames = streamFrames;
    44        }
    45  
    46        if (frames === streamFrames) {
    47          data = queryParams.plain ? frames[streamPointer] : logEncode(frames, streamPointer);
    48          streamPointer++;
    49        } else {
    50          data = queryParams.plain ? frames.join('') : logEncode(frames, frames.length - 1);
    51        }
    52  
    53        return [200, {}, data];
    54      };
    55  
    56      this.server = new Pretender(function() {
    57        this.get(`http://${HOST}/v1/client/fs/logs/:allocation_id`, handler);
    58        this.get('/v1/client/fs/logs/:allocation_id', handler);
    59        this.get('/v1/regions', () => [200, {}, '[]']);
    60      });
    61    });
    62  
    63    hooks.afterEach(function() {
    64      this.server.shutdown();
    65      streamPointer = 0;
    66      logMode = null;
    67    });
    68  
    69    test('Basic appearance', async function(assert) {
    70      run.later(run, run.cancelTimers, commonProps.interval);
    71  
    72      this.setProperties(commonProps);
    73      await render(hbs`{{task-log allocation=allocation task=task}}`);
    74  
    75      assert.ok(find('[data-test-log-action="stdout"]'), 'Stdout button');
    76      assert.ok(find('[data-test-log-action="stderr"]'), 'Stderr button');
    77      assert.ok(find('[data-test-log-action="head"]'), 'Head button');
    78      assert.ok(find('[data-test-log-action="tail"]'), 'Tail button');
    79      assert.ok(find('[data-test-log-action="toggle-stream"]'), 'Stream toggle button');
    80  
    81      assert.ok(find('[data-test-log-box].is-full-bleed.is-dark'), 'Body is full-bleed and dark');
    82  
    83      assert.ok(
    84        find('pre.cli-window'),
    85        'Cli is preformatted and using the cli-window component class'
    86      );
    87    });
    88  
    89    test('Streaming starts on creation', async function(assert) {
    90      run.later(run, run.cancelTimers, commonProps.interval);
    91  
    92      this.setProperties(commonProps);
    93      await render(hbs`{{task-log allocation=allocation task=task}}`);
    94  
    95      const logUrlRegex = new RegExp(`${HOST}/v1/client/fs/logs/${commonProps.allocation.id}`);
    96      assert.ok(
    97        this.server.handledRequests.filter(req => logUrlRegex.test(req.url)).length,
    98        'Log requests were made'
    99      );
   100  
   101      await settled();
   102      assert.equal(
   103        find('[data-test-log-cli]').textContent,
   104        streamFrames[0],
   105        'First chunk of streaming log is shown'
   106      );
   107    });
   108  
   109    test('Clicking Head loads the log head', async function(assert) {
   110      logMode = 'head';
   111      run.later(run, run.cancelTimers, commonProps.interval);
   112  
   113      this.setProperties(commonProps);
   114      await render(hbs`{{task-log allocation=allocation task=task}}`);
   115  
   116      click('[data-test-log-action="head"]');
   117  
   118      await settled();
   119      assert.ok(
   120        this.server.handledRequests.find(
   121          ({ queryParams: qp }) => qp.origin === 'start' && qp.offset === '0'
   122        ),
   123        'Log head request was made'
   124      );
   125      assert.equal(find('[data-test-log-cli]').textContent, logHead[0], 'Head of the log is shown');
   126    });
   127  
   128    test('Clicking Tail loads the log tail', async function(assert) {
   129      logMode = 'tail';
   130      run.later(run, run.cancelTimers, commonProps.interval);
   131  
   132      this.setProperties(commonProps);
   133      await render(hbs`{{task-log allocation=allocation task=task}}`);
   134  
   135      click('[data-test-log-action="tail"]');
   136  
   137      await settled();
   138      assert.ok(
   139        this.server.handledRequests.find(({ queryParams: qp }) => qp.origin === 'end'),
   140        'Log tail request was made'
   141      );
   142      assert.equal(find('[data-test-log-cli]').textContent, logTail[0], 'Tail of the log is shown');
   143    });
   144  
   145    test('Clicking toggleStream starts and stops the log stream', async function(assert) {
   146      run.later(run, run.cancelTimers, commonProps.interval);
   147  
   148      const { interval } = commonProps;
   149      this.setProperties(commonProps);
   150      await render(hbs`{{task-log allocation=allocation task=task interval=interval}}`);
   151  
   152      run.later(() => {
   153        click('[data-test-log-action="toggle-stream"]');
   154      }, interval);
   155  
   156      await settled();
   157      assert.equal(find('[data-test-log-cli]').textContent, streamFrames[0], 'First frame loaded');
   158  
   159      run.later(() => {
   160        assert.equal(
   161          find('[data-test-log-cli]').textContent,
   162          streamFrames[0],
   163          'Still only first frame'
   164        );
   165        click('[data-test-log-action="toggle-stream"]');
   166        run.later(run, run.cancelTimers, interval * 2);
   167      }, interval * 2);
   168  
   169      await settled();
   170      assert.equal(
   171        find('[data-test-log-cli]').textContent,
   172        streamFrames[0] + streamFrames[0] + streamFrames[1],
   173        'Now includes second frame'
   174      );
   175    });
   176  
   177    test('Clicking stderr switches the log to standard error', async function(assert) {
   178      run.later(run, run.cancelTimers, commonProps.interval);
   179  
   180      this.setProperties(commonProps);
   181      await render(hbs`{{task-log allocation=allocation task=task}}`);
   182  
   183      click('[data-test-log-action="stderr"]');
   184      run.later(run, run.cancelTimers, commonProps.interval);
   185  
   186      await settled();
   187      assert.ok(
   188        this.server.handledRequests.filter(req => req.queryParams.type === 'stderr').length,
   189        'stderr log requests were made'
   190      );
   191    });
   192  
   193    test('Clicking stderr/stdout mode buttons does nothing when the mode remains the same', async function(assert) {
   194      const { interval } = commonProps;
   195  
   196      run.later(() => {
   197        click('[data-test-log-action="stdout"]');
   198        run.later(run, run.cancelTimers, interval * 6);
   199      }, interval * 2);
   200  
   201      this.setProperties(commonProps);
   202      await render(hbs`{{task-log allocation=allocation task=task}}`);
   203  
   204      await settled();
   205      assert.equal(
   206        find('[data-test-log-cli]').textContent,
   207        streamFrames[0] + streamFrames[0] + streamFrames[1],
   208        'Now includes second frame'
   209      );
   210    });
   211  
   212    test('When the client is inaccessible, task-log falls back to requesting logs through the server', async function(assert) {
   213      run.later(run, run.cancelTimers, allowedConnectionTime * 2);
   214  
   215      // override client response to timeout
   216      this.server.get(
   217        `http://${HOST}/v1/client/fs/logs/:allocation_id`,
   218        () => [400, {}, ''],
   219        allowedConnectionTime * 2
   220      );
   221  
   222      this.setProperties(commonProps);
   223      await render(hbs`{{task-log
   224        allocation=allocation
   225        task=task
   226        clientTimeout=clientTimeout
   227        serverTimeout=serverTimeout}}`);
   228  
   229      const clientUrlRegex = new RegExp(`${HOST}/v1/client/fs/logs/${commonProps.allocation.id}`);
   230      assert.ok(
   231        this.server.handledRequests.filter(req => clientUrlRegex.test(req.url)).length,
   232        'Log request was initially made directly to the client'
   233      );
   234  
   235      await settled();
   236      const serverUrl = `/v1/client/fs/logs/${commonProps.allocation.id}`;
   237      assert.ok(
   238        this.server.handledRequests.filter(req => req.url.startsWith(serverUrl)).length,
   239        'Log request was later made to the server'
   240      );
   241  
   242      assert.ok(
   243        this.server.handledRequests.filter(req => clientUrlRegex.test(req.url))[0].aborted,
   244        'Client log request was aborted'
   245      );
   246    });
   247  
   248    test('When both the client and the server are inaccessible, an error message is shown', async function(assert) {
   249      run.later(run, run.cancelTimers, allowedConnectionTime * 5);
   250  
   251      // override client and server responses to timeout
   252      this.server.get(
   253        `http://${HOST}/v1/client/fs/logs/:allocation_id`,
   254        () => [400, {}, ''],
   255        allowedConnectionTime * 2
   256      );
   257      this.server.get(
   258        '/v1/client/fs/logs/:allocation_id',
   259        () => [400, {}, ''],
   260        allowedConnectionTime * 2
   261      );
   262  
   263      this.setProperties(commonProps);
   264      await render(hbs`{{task-log
   265        allocation=allocation
   266        task=task
   267        clientTimeout=clientTimeout
   268        serverTimeout=serverTimeout}}`);
   269  
   270      await settled();
   271      const clientUrlRegex = new RegExp(`${HOST}/v1/client/fs/logs/${commonProps.allocation.id}`);
   272      assert.ok(
   273        this.server.handledRequests.filter(req => clientUrlRegex.test(req.url)).length,
   274        'Log request was initially made directly to the client'
   275      );
   276      const serverUrl = `/v1/client/fs/logs/${commonProps.allocation.id}`;
   277      assert.ok(
   278        this.server.handledRequests.filter(req => req.url.startsWith(serverUrl)).length,
   279        'Log request was later made to the server'
   280      );
   281      assert.ok(find('[data-test-connection-error]'), 'An error message is shown');
   282  
   283      await click('[data-test-connection-error-dismiss]');
   284      assert.notOk(find('[data-test-connection-error]'), 'The error message is dismissable');
   285    });
   286  
   287    test('When the client is inaccessible, the server is accessible, and stderr is pressed before the client timeout occurs, the no connection error is not shown', async function(assert) {
   288      // override client response to timeout
   289      this.server.get(
   290        `http://${HOST}/v1/client/fs/logs/:allocation_id`,
   291        () => [400, {}, ''],
   292        allowedConnectionTime * 2
   293      );
   294  
   295      // Click stderr before the client request responds
   296      run.later(() => {
   297        click('[data-test-log-action="stderr"]');
   298        run.later(run, run.cancelTimers, commonProps.interval * 5);
   299      }, allowedConnectionTime / 2);
   300  
   301      this.setProperties(commonProps);
   302      await render(hbs`{{task-log
   303        allocation=allocation
   304        task=task
   305        clientTimeout=clientTimeout
   306        serverTimeout=serverTimeout}}`);
   307  
   308      await settled();
   309  
   310      const clientUrlRegex = new RegExp(`${HOST}/v1/client/fs/logs/${commonProps.allocation.id}`);
   311      const clientRequests = this.server.handledRequests.filter(req => clientUrlRegex.test(req.url));
   312      assert.ok(
   313        clientRequests.find(req => req.queryParams.type === 'stdout'),
   314        'Client request for stdout'
   315      );
   316      assert.ok(
   317        clientRequests.find(req => req.queryParams.type === 'stderr'),
   318        'Client request for stderr'
   319      );
   320  
   321      const serverUrl = `/v1/client/fs/logs/${commonProps.allocation.id}`;
   322      assert.ok(
   323        this.server.handledRequests
   324          .filter(req => req.url.startsWith(serverUrl))
   325          .find(req => req.queryParams.type === 'stderr'),
   326        'Server request for stderr'
   327      );
   328  
   329      assert.notOk(find('[data-test-connection-error]'), 'An error message is not shown');
   330    });
   331  });