github.com/aminovpavel/nomad@v0.11.8/ui/tests/acceptance/behaviors/fs.js (about)

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