github.com/iqoqo/nomad@v0.11.3-0.20200911112621-d7021c74d101/ui/tests/acceptance/task-fs-test.js (about)

     1  import { currentURL, visit } from '@ember/test-helpers';
     2  import { Promise } from 'rsvp';
     3  import { module, test } from 'qunit';
     4  import { setupApplicationTest } from 'ember-qunit';
     5  import moment from 'moment';
     6  
     7  import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
     8  import Response from 'ember-cli-mirage/response';
     9  
    10  import { formatBytes } from 'nomad-ui/helpers/format-bytes';
    11  import { filesForPath } from 'nomad-ui/mirage/config';
    12  
    13  import FS from 'nomad-ui/tests/pages/allocations/task/fs';
    14  
    15  let allocation;
    16  let task;
    17  let files;
    18  
    19  const fileSort = (prop, files) => {
    20    let dir = [];
    21    let file = [];
    22    files.forEach(f => {
    23      if (f.isDir) {
    24        dir.push(f);
    25      } else {
    26        file.push(f);
    27      }
    28    });
    29  
    30    return dir.sortBy(prop).concat(file.sortBy(prop));
    31  };
    32  
    33  module('Acceptance | task fs', function(hooks) {
    34    setupApplicationTest(hooks);
    35    setupMirage(hooks);
    36  
    37    hooks.beforeEach(async function() {
    38      server.create('agent');
    39      server.create('node', 'forceIPv4');
    40      const job = server.create('job', { createAllocations: false });
    41  
    42      allocation = server.create('allocation', { jobId: job.id, clientStatus: 'running' });
    43      task = server.schema.taskStates.where({ allocationId: allocation.id }).models[0];
    44      task.name = 'task-name';
    45      task.save();
    46  
    47      // Reset files
    48      files = [];
    49  
    50      // Nested files
    51      files.push(server.create('allocFile', { isDir: true, name: 'directory' }));
    52      files.push(server.create('allocFile', { isDir: true, name: 'another', parent: files[0] }));
    53      files.push(
    54        server.create('allocFile', 'file', {
    55          name: 'something.txt',
    56          fileType: 'txt',
    57          parent: files[1],
    58        })
    59      );
    60  
    61      files.push(server.create('allocFile', { isDir: true, name: 'empty-directory' }));
    62      files.push(server.create('allocFile', 'file', { fileType: 'txt' }));
    63      files.push(server.create('allocFile', 'file', { fileType: 'txt' }));
    64    });
    65  
    66    test('visiting /allocations/:allocation_id/:task_name/fs', async function(assert) {
    67      await FS.visit({ id: allocation.id, name: task.name });
    68      assert.equal(currentURL(), `/allocations/${allocation.id}/${task.name}/fs`, 'No redirect');
    69    });
    70  
    71    test('when the task is not running, an empty state is shown', async function(assert) {
    72      // The API 500s on stat when not running
    73      this.server.get('/client/fs/stat/:allocation_id', () => {
    74        return new Response(500, {}, 'no such file or directory');
    75      });
    76  
    77      task.update({
    78        finishedAt: new Date(),
    79      });
    80  
    81      await FS.visit({ id: allocation.id, name: task.name });
    82      assert.ok(FS.hasEmptyState, 'Non-running task has no files');
    83      assert.ok(
    84        FS.emptyState.headline.includes('Task is not Running'),
    85        'Empty state explains the condition'
    86      );
    87    });
    88  
    89    test('visiting /allocations/:allocation_id/:task_name/fs/:path', async function(assert) {
    90      const paths = ['some-file.log', 'a/deep/path/to/a/file.log', '/', 'Unicode™®'];
    91  
    92      const testPath = async filePath => {
    93        let pathWithLeadingSlash = filePath;
    94  
    95        if (!pathWithLeadingSlash.startsWith('/')) {
    96          pathWithLeadingSlash = `/${filePath}`;
    97        }
    98  
    99        await FS.visitPath({ id: allocation.id, name: task.name, path: filePath });
   100        assert.equal(
   101          currentURL(),
   102          `/allocations/${allocation.id}/${task.name}/fs/${encodeURIComponent(filePath)}`,
   103          'No redirect'
   104        );
   105        assert.equal(
   106          document.title,
   107          `${pathWithLeadingSlash} - Task ${task.name} filesystem - Nomad`
   108        );
   109        assert.equal(FS.breadcrumbsText, `${task.name} ${filePath.replace(/\//g, ' ')}`.trim());
   110      };
   111  
   112      await paths.reduce(async (prev, filePath) => {
   113        await prev;
   114        return testPath(filePath);
   115      }, Promise.resolve());
   116    });
   117  
   118    test('navigating allocation filesystem', async function(assert) {
   119      await FS.visitPath({ id: allocation.id, name: task.name, path: '/' });
   120  
   121      const sortedFiles = fileSort('name', filesForPath(this.server.schema.allocFiles, '').models);
   122  
   123      assert.ok(FS.fileViewer.isHidden);
   124  
   125      assert.equal(FS.directoryEntries.length, 4);
   126  
   127      assert.equal(FS.breadcrumbsText, task.name);
   128  
   129      assert.equal(FS.breadcrumbs.length, 1);
   130      assert.ok(FS.breadcrumbs[0].isActive);
   131      assert.equal(FS.breadcrumbs[0].text, 'task-name');
   132  
   133      FS.directoryEntries[0].as(directory => {
   134        const fileRecord = sortedFiles[0];
   135        assert.equal(directory.name, fileRecord.name, 'directories should come first');
   136        assert.ok(directory.isDirectory);
   137        assert.equal(directory.size, '', 'directory sizes are hidden');
   138        assert.equal(directory.lastModified, moment(fileRecord.modTime).fromNow());
   139        assert.notOk(directory.path.includes('//'), 'paths shouldn’t have redundant separators');
   140      });
   141  
   142      FS.directoryEntries[2].as(file => {
   143        const fileRecord = sortedFiles[2];
   144        assert.equal(file.name, fileRecord.name);
   145        assert.ok(file.isFile);
   146        assert.equal(file.size, formatBytes([fileRecord.size]));
   147        assert.equal(file.lastModified, moment(fileRecord.modTime).fromNow());
   148      });
   149  
   150      await FS.directoryEntries[0].visit();
   151  
   152      assert.equal(FS.directoryEntries.length, 1);
   153  
   154      assert.equal(FS.breadcrumbs.length, 2);
   155      assert.equal(FS.breadcrumbsText, `${task.name} ${files[0].name}`);
   156  
   157      assert.notOk(FS.breadcrumbs[0].isActive);
   158  
   159      assert.equal(FS.breadcrumbs[1].text, files[0].name);
   160      assert.ok(FS.breadcrumbs[1].isActive);
   161  
   162      await FS.directoryEntries[0].visit();
   163  
   164      assert.equal(FS.directoryEntries.length, 1);
   165      assert.notOk(
   166        FS.directoryEntries[0].path.includes('//'),
   167        'paths shouldn’t have redundant separators'
   168      );
   169  
   170      assert.equal(FS.breadcrumbs.length, 3);
   171      assert.equal(FS.breadcrumbsText, `${task.name} ${files[0].name} ${files[1].name}`);
   172      assert.equal(FS.breadcrumbs[2].text, files[1].name);
   173  
   174      assert.notOk(
   175        FS.breadcrumbs[0].path.includes('//'),
   176        'paths shouldn’t have redundant separators'
   177      );
   178      assert.notOk(
   179        FS.breadcrumbs[1].path.includes('//'),
   180        'paths shouldn’t have redundant separators'
   181      );
   182  
   183      await FS.breadcrumbs[1].visit();
   184      assert.equal(FS.breadcrumbsText, `${task.name} ${files[0].name}`);
   185      assert.equal(FS.breadcrumbs.length, 2);
   186    });
   187  
   188    test('sorting allocation filesystem directory', async function(assert) {
   189      this.server.get('/client/fs/ls/:allocation_id', () => {
   190        return [
   191          {
   192            Name: 'aaa-big-old-file',
   193            IsDir: false,
   194            Size: 19190000,
   195            ModTime: moment()
   196              .subtract(1, 'year')
   197              .format(),
   198          },
   199          {
   200            Name: 'mmm-small-mid-file',
   201            IsDir: false,
   202            Size: 1919,
   203            ModTime: moment()
   204              .subtract(6, 'month')
   205              .format(),
   206          },
   207          {
   208            Name: 'zzz-med-new-file',
   209            IsDir: false,
   210            Size: 191900,
   211            ModTime: moment().format(),
   212          },
   213          {
   214            Name: 'aaa-big-old-directory',
   215            IsDir: true,
   216            Size: 19190000,
   217            ModTime: moment()
   218              .subtract(1, 'year')
   219              .format(),
   220          },
   221          {
   222            Name: 'mmm-small-mid-directory',
   223            IsDir: true,
   224            Size: 1919,
   225            ModTime: moment()
   226              .subtract(6, 'month')
   227              .format(),
   228          },
   229          {
   230            Name: 'zzz-med-new-directory',
   231            IsDir: true,
   232            Size: 191900,
   233            ModTime: moment().format(),
   234          },
   235        ];
   236      });
   237  
   238      await FS.visitPath({ id: allocation.id, name: task.name, path: '/' });
   239  
   240      assert.deepEqual(FS.directoryEntryNames(), [
   241        'aaa-big-old-directory',
   242        'mmm-small-mid-directory',
   243        'zzz-med-new-directory',
   244        'aaa-big-old-file',
   245        'mmm-small-mid-file',
   246        'zzz-med-new-file',
   247      ]);
   248  
   249      await FS.sortBy('Name');
   250  
   251      assert.deepEqual(FS.directoryEntryNames(), [
   252        'zzz-med-new-file',
   253        'mmm-small-mid-file',
   254        'aaa-big-old-file',
   255        'zzz-med-new-directory',
   256        'mmm-small-mid-directory',
   257        'aaa-big-old-directory',
   258      ]);
   259  
   260      await FS.sortBy('ModTime');
   261  
   262      assert.deepEqual(FS.directoryEntryNames(), [
   263        'zzz-med-new-file',
   264        'mmm-small-mid-file',
   265        'aaa-big-old-file',
   266        'zzz-med-new-directory',
   267        'mmm-small-mid-directory',
   268        'aaa-big-old-directory',
   269      ]);
   270  
   271      await FS.sortBy('ModTime');
   272  
   273      assert.deepEqual(FS.directoryEntryNames(), [
   274        'aaa-big-old-directory',
   275        'mmm-small-mid-directory',
   276        'zzz-med-new-directory',
   277        'aaa-big-old-file',
   278        'mmm-small-mid-file',
   279        'zzz-med-new-file',
   280      ]);
   281  
   282      await FS.sortBy('Size');
   283  
   284      assert.deepEqual(
   285        FS.directoryEntryNames(),
   286        [
   287          'aaa-big-old-file',
   288          'zzz-med-new-file',
   289          'mmm-small-mid-file',
   290          'zzz-med-new-directory',
   291          'mmm-small-mid-directory',
   292          'aaa-big-old-directory',
   293        ],
   294        'expected files to be sorted by descending size and directories to be sorted by descending name'
   295      );
   296  
   297      await FS.sortBy('Size');
   298  
   299      assert.deepEqual(
   300        FS.directoryEntryNames(),
   301        [
   302          'aaa-big-old-directory',
   303          'mmm-small-mid-directory',
   304          'zzz-med-new-directory',
   305          'mmm-small-mid-file',
   306          'zzz-med-new-file',
   307          'aaa-big-old-file',
   308        ],
   309        'expected directories to be sorted by name and files to be sorted by ascending size'
   310      );
   311    });
   312  
   313    test('viewing a file', async function(assert) {
   314      const node = server.db.nodes.find(allocation.nodeId);
   315  
   316      server.get(`http://${node.httpAddr}/v1/client/fs/readat/:allocation_id`, function() {
   317        return new Response(500);
   318      });
   319  
   320      await FS.visitPath({ id: allocation.id, name: task.name, path: '/' });
   321  
   322      const sortedFiles = fileSort('name', filesForPath(this.server.schema.allocFiles, '').models);
   323      const fileRecord = sortedFiles.find(f => !f.isDir);
   324      const fileIndex = sortedFiles.indexOf(fileRecord);
   325  
   326      await FS.directoryEntries[fileIndex].visit();
   327  
   328      assert.equal(FS.breadcrumbsText, `${task.name} ${fileRecord.name}`);
   329  
   330      assert.ok(FS.fileViewer.isPresent);
   331  
   332      const requests = this.server.pretender.handledRequests;
   333      const secondAttempt = requests.pop();
   334      const firstAttempt = requests.pop();
   335  
   336      assert.equal(
   337        firstAttempt.url.split('?')[0],
   338        `//${node.httpAddr}/v1/client/fs/readat/${allocation.id}`,
   339        'Client is hit first'
   340      );
   341      assert.equal(firstAttempt.status, 500, 'Client request fails');
   342      assert.equal(
   343        secondAttempt.url.split('?')[0],
   344        `/v1/client/fs/readat/${allocation.id}`,
   345        'Server is hit second'
   346      );
   347    });
   348  
   349    test('viewing an empty directory', async function(assert) {
   350      await FS.visitPath({ id: allocation.id, name: task.name, path: '/empty-directory' });
   351  
   352      assert.ok(FS.isEmptyDirectory);
   353    });
   354  
   355    test('viewing paths that produce stat API errors', async function(assert) {
   356      this.server.get('/client/fs/stat/:allocation_id', () => {
   357        return new Response(500, {}, 'no such file or directory');
   358      });
   359  
   360      await FS.visitPath({ id: allocation.id, name: task.name, path: '/what-is-this' });
   361      assert.equal(FS.error.title, 'Not Found', '500 is interpreted as 404');
   362  
   363      await visit('/');
   364  
   365      this.server.get('/client/fs/stat/:allocation_id', () => {
   366        return new Response(999);
   367      });
   368  
   369      await FS.visitPath({ id: allocation.id, name: task.name, path: '/what-is-this' });
   370      assert.equal(FS.error.title, 'Error', 'other statuses are passed through');
   371    });
   372  
   373    test('viewing paths that produce ls API errors', async function(assert) {
   374      this.server.get('/client/fs/ls/:allocation_id', () => {
   375        return new Response(500, {}, 'no such file or directory');
   376      });
   377  
   378      await FS.visitPath({ id: allocation.id, name: task.name, path: files[0].name });
   379      assert.equal(FS.error.title, 'Not Found', '500 is interpreted as 404');
   380  
   381      await visit('/');
   382  
   383      this.server.get('/client/fs/ls/:allocation_id', () => {
   384        return new Response(999);
   385      });
   386  
   387      await FS.visitPath({ id: allocation.id, name: task.name, path: files[0].name });
   388      assert.equal(FS.error.title, 'Error', 'other statuses are passed through');
   389    });
   390  });