github.com/ferranbt/nomad@v0.9.3-0.20190607002617-85c449b7667c/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 { render, settled } from '@ember/test-helpers'; 5 import { find, click } from 'ember-native-dom-helpers'; 6 import hbs from 'htmlbars-inline-precompile'; 7 import Pretender from 'pretender'; 8 import { logEncode } from '../../mirage/data/logs'; 9 10 const HOST = '1.1.1.1:1111'; 11 const allowedConnectionTime = 100; 12 const commonProps = { 13 interval: 200, 14 allocation: { 15 id: 'alloc-1', 16 node: { 17 httpAddr: HOST, 18 }, 19 }, 20 task: 'task-name', 21 clientTimeout: allowedConnectionTime, 22 serverTimeout: allowedConnectionTime, 23 }; 24 25 const logHead = ['HEAD']; 26 const logTail = ['TAIL']; 27 const streamFrames = ['one\n', 'two\n', 'three\n', 'four\n', 'five\n']; 28 let streamPointer = 0; 29 30 module('Integration | Component | task log', function(hooks) { 31 setupRenderingTest(hooks); 32 33 hooks.beforeEach(function() { 34 const handler = ({ queryParams }) => { 35 const { origin, offset, plain, follow } = queryParams; 36 37 let frames; 38 let data; 39 40 if (origin === 'start' && offset === '0' && plain && !follow) { 41 frames = logHead; 42 } else if (origin === 'end' && plain && !follow) { 43 frames = logTail; 44 } else { 45 frames = streamFrames; 46 } 47 48 if (frames === streamFrames) { 49 data = queryParams.plain ? frames[streamPointer] : logEncode(frames, streamPointer); 50 streamPointer++; 51 } else { 52 data = queryParams.plain ? frames.join('') : logEncode(frames, frames.length - 1); 53 } 54 55 return [200, {}, data]; 56 }; 57 58 this.server = new Pretender(function() { 59 this.get(`http://${HOST}/v1/client/fs/logs/:allocation_id`, handler); 60 this.get('/v1/client/fs/logs/:allocation_id', handler); 61 this.get('/v1/regions', () => [200, {}, '[]']); 62 }); 63 }); 64 65 hooks.afterEach(function() { 66 this.server.shutdown(); 67 streamPointer = 0; 68 }); 69 70 test('Basic appearance', async function(assert) { 71 run.later(run, run.cancelTimers, commonProps.interval); 72 73 this.setProperties(commonProps); 74 await render(hbs`{{task-log allocation=allocation task=task}}`); 75 76 assert.ok(find('[data-test-log-action="stdout"]'), 'Stdout button'); 77 assert.ok(find('[data-test-log-action="stderr"]'), 'Stderr button'); 78 assert.ok(find('[data-test-log-action="head"]'), 'Head button'); 79 assert.ok(find('[data-test-log-action="tail"]'), 'Tail button'); 80 assert.ok(find('[data-test-log-action="toggle-stream"]'), 'Stream toggle button'); 81 82 assert.ok(find('[data-test-log-box].is-full-bleed.is-dark'), 'Body is full-bleed and dark'); 83 84 assert.ok( 85 find('pre.cli-window'), 86 'Cli is preformatted and using the cli-window component class' 87 ); 88 }); 89 90 test('Streaming starts on creation', async function(assert) { 91 run.later(run, run.cancelTimers, commonProps.interval); 92 93 this.setProperties(commonProps); 94 await render(hbs`{{task-log allocation=allocation task=task}}`); 95 96 const logUrlRegex = new RegExp(`${HOST}/v1/client/fs/logs/${commonProps.allocation.id}`); 97 assert.ok( 98 this.server.handledRequests.filter(req => logUrlRegex.test(req.url)).length, 99 'Log requests were made' 100 ); 101 102 await settled(); 103 assert.equal( 104 find('[data-test-log-cli]').textContent, 105 streamFrames[0], 106 'First chunk of streaming log is shown' 107 ); 108 }); 109 110 test('Clicking Head loads the log head', async function(assert) { 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.plain === 'true' && 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 run.later(run, run.cancelTimers, commonProps.interval); 130 131 this.setProperties(commonProps); 132 await render(hbs`{{task-log allocation=allocation task=task}}`); 133 134 click('[data-test-log-action="tail"]'); 135 136 await settled(); 137 assert.ok( 138 this.server.handledRequests.find( 139 ({ queryParams: qp }) => qp.origin === 'end' && qp.plain === 'true' 140 ), 141 'Log tail request was made' 142 ); 143 assert.equal(find('[data-test-log-cli]').textContent, logTail[0], 'Tail of the log is shown'); 144 }); 145 146 test('Clicking toggleStream starts and stops the log stream', async function(assert) { 147 run.later(run, run.cancelTimers, commonProps.interval); 148 149 const { interval } = commonProps; 150 this.setProperties(commonProps); 151 await render(hbs`{{task-log allocation=allocation task=task interval=interval}}`); 152 153 run.later(() => { 154 click('[data-test-log-action="toggle-stream"]'); 155 }, interval); 156 157 await settled(); 158 assert.equal(find('[data-test-log-cli]').textContent, streamFrames[0], 'First frame loaded'); 159 160 run.later(() => { 161 assert.equal( 162 find('[data-test-log-cli]').textContent, 163 streamFrames[0], 164 'Still only first frame' 165 ); 166 click('[data-test-log-action="toggle-stream"]'); 167 run.later(run, run.cancelTimers, interval * 2); 168 }, interval * 2); 169 170 await settled(); 171 assert.equal( 172 find('[data-test-log-cli]').textContent, 173 streamFrames[0] + streamFrames[0] + streamFrames[1], 174 'Now includes second frame' 175 ); 176 }); 177 178 test('Clicking stderr switches the log to standard error', async function(assert) { 179 run.later(run, run.cancelTimers, commonProps.interval); 180 181 this.setProperties(commonProps); 182 await render(hbs`{{task-log allocation=allocation task=task}}`); 183 184 click('[data-test-log-action="stderr"]'); 185 run.later(run, run.cancelTimers, commonProps.interval); 186 187 await settled(); 188 assert.ok( 189 this.server.handledRequests.filter(req => req.queryParams.type === 'stderr').length, 190 'stderr log requests were made' 191 ); 192 }); 193 194 test('When the client is inaccessible, task-log falls back to requesting logs through the server', async function(assert) { 195 run.later(run, run.cancelTimers, allowedConnectionTime * 2); 196 197 // override client response to timeout 198 this.server.get( 199 `http://${HOST}/v1/client/fs/logs/:allocation_id`, 200 () => [400, {}, ''], 201 allowedConnectionTime * 2 202 ); 203 204 this.setProperties(commonProps); 205 await render(hbs`{{task-log 206 allocation=allocation 207 task=task 208 clientTimeout=clientTimeout 209 serverTimeout=serverTimeout}}`); 210 211 const clientUrlRegex = new RegExp(`${HOST}/v1/client/fs/logs/${commonProps.allocation.id}`); 212 assert.ok( 213 this.server.handledRequests.filter(req => clientUrlRegex.test(req.url)).length, 214 'Log request was initially made directly to the client' 215 ); 216 217 await settled(); 218 const serverUrl = `/v1/client/fs/logs/${commonProps.allocation.id}`; 219 assert.ok( 220 this.server.handledRequests.filter(req => req.url.startsWith(serverUrl)).length, 221 'Log request was later made to the server' 222 ); 223 }); 224 225 test('When both the client and the server are inaccessible, an error message is shown', async function(assert) { 226 run.later(run, run.cancelTimers, allowedConnectionTime * 5); 227 228 // override client and server responses to timeout 229 this.server.get( 230 `http://${HOST}/v1/client/fs/logs/:allocation_id`, 231 () => [400, {}, ''], 232 allowedConnectionTime * 2 233 ); 234 this.server.get( 235 '/v1/client/fs/logs/:allocation_id', 236 () => [400, {}, ''], 237 allowedConnectionTime * 2 238 ); 239 240 this.setProperties(commonProps); 241 await render(hbs`{{task-log 242 allocation=allocation 243 task=task 244 clientTimeout=clientTimeout 245 serverTimeout=serverTimeout}}`); 246 247 await settled(); 248 const clientUrlRegex = new RegExp(`${HOST}/v1/client/fs/logs/${commonProps.allocation.id}`); 249 assert.ok( 250 this.server.handledRequests.filter(req => clientUrlRegex.test(req.url)).length, 251 'Log request was initially made directly to the client' 252 ); 253 const serverUrl = `/v1/client/fs/logs/${commonProps.allocation.id}`; 254 assert.ok( 255 this.server.handledRequests.filter(req => req.url.startsWith(serverUrl)).length, 256 'Log request was later made to the server' 257 ); 258 assert.ok(find('[data-test-connection-error]'), 'An error message is shown'); 259 }); 260 });