Commit 19ba9601 authored by Andreas Haas's avatar Andreas Haas Committed by moz-wptsync-bot
Browse files

Bug 1719640 [wpt PR 29609] - [fsa] Implement read and write for the sync access handle, a=testonly

Automatic update from web-platform-tests
[fsa] Implement read and write for the sync access handle

The implementation is ported from the implementation of
Storage Foundation in
https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/modules/native_io/native_io_file_sync.cc.

This is part of the efforts to merge Storage Foundation into OPFS.

Bug: chromium:1218431
Change-Id: Ibbd3288fa198f3fc3ce135c6b056fde9d2c02909
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3014235


Commit-Queue: Andreas Haas <ahaas@chromium.org>
Reviewed-by: default avatarMarijn Kruisselbrink <mek@chromium.org>
Cr-Commit-Position: refs/heads/master@{#903781}

--

wpt-commits: 03d01f21e8fa92829c2c027b85f45ffb24cc4992
wpt-pr: 29609
parent 38a95bdd
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
async function cleanupSandboxedFileSystem() {
  const dir = await navigator.storage.getDirectory();
  for await (let entry of dir.values())
    await dir.removeEntry(entry.name, {recursive: entry.kind === 'directory'});
}

function sync_access_handle_test(test, description) {
  promise_test(async t => {
    // To be extra resilient against bad tests, cleanup before every test.
    await cleanupSandboxedFileSystem();

    const dir = await navigator.storage.getDirectory();
    const fileHandle = await dir.getFileHandle('OPFS.test', {create: true});
    const syncHandle = await fileHandle.createSyncAccessHandle();
    await test(t, syncHandle);
  }, description);
}
+183 −0
Original line number Diff line number Diff line
importScripts("/resources/testharness.js");
importScripts('resources/sync-access-handle-test.js');

'use strict';

sync_access_handle_test((t, handle) => {
  const readBuffer = new Uint8Array(24);
  const readBytes = handle.read(readBuffer, {at: 0});
  assert_equals(0, readBytes, 'Check that no bytes were read');
}, 'Test reading an empty file through a sync access handle.');

sync_access_handle_test((t, handle) => {
  if (!('TextEncoder' in self)) {
    return;
  }
  const encoder = new TextEncoder();
  const decoder = new TextDecoder();

  const text = 'Hello Storage Foundation';
  const writeBuffer = new TextEncoder().encode(text);
  const writtenBytes = handle.write(writeBuffer, {at: 0});
  assert_equals(
      writeBuffer.byteLength, writtenBytes,
      'Check that all bytes were written.');
  let readBuffer = new Uint8Array(writtenBytes);
  let readBytes = handle.read(readBuffer, {at: 0});
  assert_equals(writtenBytes, readBytes, 'Check that all bytes were read');
  assert_equals(
      text, new TextDecoder().decode(readBuffer),
      'Check that the written bytes and the read bytes match');

  // Test a read of less bytes than available.
  const expected = 'Storage';
  readBuffer = new Uint8Array(expected.length);
  readBytes = handle.read(readBuffer, {at: text.indexOf(expected)});
  assert_equals(readBuffer.length, readBytes, 'Check that all bytes were read');
  const actual = new TextDecoder().decode(readBuffer);
  assert_equals(
      expected, actual,
      'Partial read returned unexpected contents');
}, 'Test writing and reading through a sync access handle.');

sync_access_handle_test((t, handle) => {
  if (!('TextEncoder' in self)) {
    return;
  }

  const encoder = new TextEncoder();
  const decoder = new TextDecoder();

  for (text of ['Hello', 'Longer Text']) {
    const writeBuffer = new TextEncoder().encode(text);
    const writtenBytes = handle.write(writeBuffer, {at: 0});
    assert_equals(
        writeBuffer.byteLength, writtenBytes,
        'Check that all bytes were written.');
    const readBuffer = new Uint8Array(writtenBytes);
    const readBytes = handle.read(readBuffer, {at: 0});
    assert_equals(writtenBytes, readBytes, 'Check that all bytes were read');
    assert_equals(
        text, new TextDecoder().decode(readBuffer),
        'Check that the written bytes and the read bytes match');
  }
}, 'Test second write that is bigger than the first write');

sync_access_handle_test((t, handle) => {
  if (!('TextEncoder' in self)) {
    return;
  }

  const encoder = new TextEncoder();
  const decoder = new TextDecoder();

  for (tuple
           of [{input: 'Hello World', expected: 'Hello World'},
               {input: 'foobar', expected: 'foobarWorld'}]) {
    const text = tuple.input;
    const expected = tuple.expected;
    const writeBuffer = new TextEncoder().encode(text);
    const writtenBytes = handle.write(writeBuffer, {at: 0});
    assert_equals(
        writeBuffer.byteLength, writtenBytes,
        'Check that all bytes were written.');
    const readBuffer = new Uint8Array(expected.length);
    const readBytes = handle.read(readBuffer, {at: 0});
    assert_equals(expected.length, readBytes, 'Check that all bytes were read');
    assert_equals(
        expected, new TextDecoder().decode(readBuffer),
        'Check that the written bytes and the read bytes match');
  }
}, 'Test second write that is smaller than the first write');

sync_access_handle_test((t, handle) => {
  const expected = 17;
  const writeBuffer = new Uint8Array(1);
  writeBuffer[0] = expected;
  const offset = 5;
  const writtenBytes = handle.write(writeBuffer, {at: offset});
  assert_equals(
      writeBuffer.byteLength, writtenBytes,
      'Check that all bytes were written.');
  const fileLength = writeBuffer.byteLength + offset;
  const readBuffer = new Uint8Array(fileLength);
  const readBytes = handle.read(readBuffer, {at: 0});
  assert_equals(fileLength, readBytes, 'Check that all bytes were read');
  for (let i = 0; i < offset; ++i) {
    assert_equals(
        readBuffer[i], 0,
        `Gaps in the file should be filled with 0, but got ${readBuffer[i]}.`);
  }

  assert_equals(
      readBuffer[offset], expected,
      'Gaps in the file should be filled with 0.');
}, 'Test initial write with an offset');

sync_access_handle_test((t, handle) => {
  if (!('TextEncoder' in self)) {
    return;
  }
  const encoder = new TextEncoder();
  const decoder = new TextDecoder();

  for (tuple
           of [{input: 'Hello World', expected: 'Hello World', offset: 0},
               {input: 'foobar', expected: 'Hello foobar', offset: 6}]) {
    const text = tuple.input;
    const expected = tuple.expected;
    const offset = tuple.offset;
    const writeBuffer = new TextEncoder().encode(text);
    const writtenBytes = handle.write(writeBuffer, {at: offset});
    assert_equals(
        writeBuffer.byteLength, writtenBytes,
        'Check that all bytes were written.');
    const readBuffer = new Uint8Array(expected.length);
    const readBytes = handle.read(readBuffer, {at: 0});
    assert_equals(expected.length, readBytes, 'Check that all bytes were read');
    const actual = new TextDecoder().decode(readBuffer);
    assert_equals(
        expected, actual,
        'Check content read from the handle');
  }
}, 'Test overwriting the file at an offset');

sync_access_handle_test((t, handle) => {
  if (!('TextEncoder' in self)) {
    return;
  }
  const encoder = new TextEncoder();
  const decoder = new TextDecoder();

  const text = 'Hello Storage Foundation';
  const writeBuffer = new TextEncoder().encode(text);
  const writtenBytes = handle.write(writeBuffer, {at: 0});
  assert_equals(
      writeBuffer.byteLength, writtenBytes,
      'Check that all bytes were written.');
  const bufferLength = text.length;
  for (tuple
           of [{offset: 0, expected: text},
               {offset: 6, expected: text.substring(6)}]) {
    const offset = tuple.offset;
    const expected = tuple.expected;

    const readBuffer = new Uint8Array(bufferLength);
    const readBytes = handle.read(readBuffer, {at: offset});
    assert_equals(expected.length, readBytes, 'Check that all bytes were read');
    const actual = new TextDecoder().decode(readBuffer);
    assert_true(
        actual.startsWith(expected),
        `Expected to read ${expected} but the actual value was ${actual}.`);
  }

  const readBuffer = new Uint8Array(bufferLength);
  // Offset is greater than the file length.
  const readBytes = handle.read(readBuffer, {at: bufferLength + 1});
  assert_equals(0, readBytes, 'Check that no bytes were read');
  for (let i = 0; i < readBuffer.byteLength; ++i) {
    assert_equals(0, readBuffer[i], 'Check that the read buffer is unchanged.');
  }
}, 'Test read at an offset');

done();