diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/floats/hit-test-floats-003.html.ini b/tests/wpt/metadata-layout-2020/css/CSS2/floats/hit-test-floats-003.html.ini new file mode 100644 index 00000000000..f29da48a2a0 --- /dev/null +++ b/tests/wpt/metadata-layout-2020/css/CSS2/floats/hit-test-floats-003.html.ini @@ -0,0 +1,4 @@ +[hit-test-floats-003.html] + [Miss float below something else] + expected: FAIL + diff --git a/tests/wpt/metadata-layout-2020/css/CSS2/floats/hit-test-floats-005.html.ini b/tests/wpt/metadata-layout-2020/css/CSS2/floats/hit-test-floats-005.html.ini deleted file mode 100644 index baa9f1a7541..00000000000 --- a/tests/wpt/metadata-layout-2020/css/CSS2/floats/hit-test-floats-005.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[hit-test-floats-005.html] - [Miss clipped float] - expected: FAIL - diff --git a/tests/wpt/metadata-layout-2020/css/css-backgrounds/subpixel-repeat-no-repeat-mix.html.ini b/tests/wpt/metadata-layout-2020/css/css-backgrounds/subpixel-repeat-no-repeat-mix.html.ini new file mode 100644 index 00000000000..452a56bb4d7 --- /dev/null +++ b/tests/wpt/metadata-layout-2020/css/css-backgrounds/subpixel-repeat-no-repeat-mix.html.ini @@ -0,0 +1,2 @@ +[subpixel-repeat-no-repeat-mix.html] + expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/css-fonts/animations/font-stretch-interpolation.html.ini b/tests/wpt/metadata-layout-2020/css/css-fonts/animations/font-stretch-interpolation.html.ini new file mode 100644 index 00000000000..9e947cd12a5 --- /dev/null +++ b/tests/wpt/metadata-layout-2020/css/css-fonts/animations/font-stretch-interpolation.html.ini @@ -0,0 +1,160 @@ +[font-stretch-interpolation.html] + [Web Animations: property from [normal\] to [ultra-expanded\] at (0.75) should be [175%\]] + expected: FAIL + + [Web Animations: property from [normal\] to [extra-expanded\] at (0) should be [normal\]] + expected: FAIL + + [Web Animations: property from [extra-condensed\] to [semi-condensed\] at (0) should be [extra-condensed\]] + expected: FAIL + + [Web Animations: property from [100%\] to [200%\] at (0.3) should be [130%\]] + expected: FAIL + + [Web Animations: property from neutral to [200%\] at (1) should be [200%\]] + expected: FAIL + + [Web Animations: property from [100%\] to [200%\] at (-0.25) should be [75%\]] + expected: FAIL + + [Web Animations: property from [ultra-condensed\] to [condensed\] at (0) should be [ultra-condensed\]] + expected: FAIL + + [Web Animations: property from [semi-condensed\] to [semi-expanded\] at (0.5) should be [normal\]] + expected: FAIL + + [Web Animations: property from [100%\] to [200%\] at (1) should be [200%\]] + expected: FAIL + + [Web Animations: property from [condensed\] to [expanded\] at (1) should be [expanded\]] + expected: FAIL + + [Web Animations: property from [ultra-condensed\] to [condensed\] at (1) should be [condensed\]] + expected: FAIL + + [Web Animations: property from neutral to [200%\] at (-0.25) should be [75%\]] + expected: FAIL + + [CSS Animations: property from [initial\] to [inherit\] at (1) should be [200%\]] + expected: FAIL + + [Web Animations: property from [initial\] to [inherit\] at (0) should be [100%\]] + expected: FAIL + + [Web Animations: property from [initial\] to [inherit\] at (1.5) should be [250%\]] + expected: FAIL + + [Web Animations: property from [100%\] to [200%\] at (0) should be [100%\]] + expected: FAIL + + [Web Animations: property from [normal\] to [extra-expanded\] at (1) should be [extra-expanded\]] + expected: FAIL + + [Web Animations: property from [condensed\] to [expanded\] at (0) should be [condensed\]] + expected: FAIL + + [Web Animations: property from [normal\] to [ultra-expanded\] at (0) should be [normal\]] + expected: FAIL + + [Web Animations: property from [condensed\] to [expanded\] at (0.75) should be [semi-expanded\]] + expected: FAIL + + [An interpolation to inherit updates correctly on a parent style change.] + expected: FAIL + + [CSS Animations: property from [initial\] to [inherit\] at (1.5) should be [250%\]] + expected: FAIL + + [Web Animations: property from [100%\] to [200%\] at (1.5) should be [250%\]] + expected: FAIL + + [Web Animations: property from [semi-condensed\] to [semi-expanded\] at (0) should be [semi-condensed\]] + expected: FAIL + + [Web Animations: property from [condensed\] to [expanded\] at (0.5) should be [normal\]] + expected: FAIL + + [Web Animations: property from [normal\] to [extra-expanded\] at (0.5) should be [expanded\]] + expected: FAIL + + [Web Animations: property from [initial\] to [inherit\] at (0.3) should be [130%\]] + expected: FAIL + + [Web Animations: property from neutral to [200%\] at (0) should be [100%\]] + expected: FAIL + + [Web Animations: property from [normal\] to [ultra-expanded\] at (1) should be [ultra-expanded\]] + expected: FAIL + + [Web Animations: property from neutral to [200%\] at (-2) should be [0%\]] + expected: FAIL + + [Web Animations: property from [extra-condensed\] to [semi-condensed\] at (1) should be [semi-condensed\]] + expected: FAIL + + [Web Animations: property from neutral to [200%\] at (1.5) should be [250%\]] + expected: FAIL + + [Web Animations: property from [normal\] to [ultra-expanded\] at (0.25) should be [expanded\]] + expected: FAIL + + [Web Animations: property from [initial\] to [inherit\] at (1) should be [200%\]] + expected: FAIL + + [Web Animations: property from [ultra-condensed\] to [condensed\] at (0.5) should be [extra-condensed\]] + expected: FAIL + + [Web Animations: property from [normal\] to [ultra-expanded\] at (-0.25) should be [condensed\]] + expected: FAIL + + [Web Animations: property from [extra-condensed\] to [semi-condensed\] at (0.5) should be [condensed\]] + expected: FAIL + + [Web Animations: property from [100%\] to [200%\] at (0.6) should be [160%\]] + expected: FAIL + + [CSS Animations: property from [initial\] to [inherit\] at (-0.25) should be [75%\]] + expected: FAIL + + [CSS Animations: property from [initial\] to [inherit\] at (-2) should be [0%\]] + expected: FAIL + + [Web Animations: property from [condensed\] to [expanded\] at (0.25) should be [semi-condensed\]] + expected: FAIL + + [Web Animations: property from neutral to [200%\] at (0.3) should be [130%\]] + expected: FAIL + + [Web Animations: property from [initial\] to [inherit\] at (-2) should be [0%\]] + expected: FAIL + + [Web Animations: property from [normal\] to [extra-expanded\] at (0.25) should be [semi-expanded\]] + expected: FAIL + + [Web Animations: property from [normal\] to [ultra-expanded\] at (0.125) should be [semi-expanded\]] + expected: FAIL + + [Web Animations: property from [semi-condensed\] to [semi-expanded\] at (1) should be [semi-expanded\]] + expected: FAIL + + [CSS Animations: property from [initial\] to [inherit\] at (0.3) should be [130%\]] + expected: FAIL + + [Web Animations: property from [normal\] to [ultra-expanded\] at (0.5) should be [extra-expanded\]] + expected: FAIL + + [Web Animations: property from [100%\] to [200%\] at (-2) should be [0%\]] + expected: FAIL + + [Web Animations: property from [initial\] to [inherit\] at (0.6) should be [160%\]] + expected: FAIL + + [CSS Animations: property from [initial\] to [inherit\] at (0.6) should be [160%\]] + expected: FAIL + + [Web Animations: property from [initial\] to [inherit\] at (-0.25) should be [75%\]] + expected: FAIL + + [Web Animations: property from neutral to [200%\] at (0.6) should be [160%\]] + expected: FAIL + diff --git a/tests/wpt/metadata-layout-2020/css/cssom-view/MediaQueryList-addListener-removeListener.html.ini b/tests/wpt/metadata-layout-2020/css/cssom-view/MediaQueryList-addListener-removeListener.html.ini index c884dc82eab..628b1fab770 100644 --- a/tests/wpt/metadata-layout-2020/css/cssom-view/MediaQueryList-addListener-removeListener.html.ini +++ b/tests/wpt/metadata-layout-2020/css/cssom-view/MediaQueryList-addListener-removeListener.html.ini @@ -2,6 +2,3 @@ [listeners are called when + diff --git a/tests/wpt/web-platform-tests/dom/nodes/DOMImplementation-createHTMLDocument-with-null-browsing-context-crash.html b/tests/wpt/web-platform-tests/dom/nodes/DOMImplementation-createHTMLDocument-with-null-browsing-context-crash.html new file mode 100644 index 00000000000..d0cd6f1f74b --- /dev/null +++ b/tests/wpt/web-platform-tests/dom/nodes/DOMImplementation-createHTMLDocument-with-null-browsing-context-crash.html @@ -0,0 +1,13 @@ + + +DOMImplementation.createHTMLDocument() + + + + + + diff --git a/tests/wpt/web-platform-tests/fetch/api/response/response-clone-iframe.window.js b/tests/wpt/web-platform-tests/fetch/api/response/response-clone-iframe.window.js new file mode 100644 index 00000000000..da54616c376 --- /dev/null +++ b/tests/wpt/web-platform-tests/fetch/api/response/response-clone-iframe.window.js @@ -0,0 +1,32 @@ +// Verify that calling Response clone() in a detached iframe doesn't crash. +// Regression test for https://crbug.com/1082688. + +'use strict'; + +promise_test(async () => { + // Wait for the document body to be available. + await new Promise(resolve => { + onload = resolve; + }); + + window.iframe = document.createElement('iframe'); + document.body.appendChild(iframe); + iframe.srcdoc = ` + +`; + + await new Promise(resolve => { + onmessage = evt => { + if (evt.data === 'okay') { + resolve(); + } + }; + }); + + // If it got here without crashing, the test passed. +}, 'clone within removed iframe should not crash'); diff --git a/tests/wpt/web-platform-tests/fetch/api/response/response-clone.html b/tests/wpt/web-platform-tests/fetch/api/response/response-clone.html index f5ebd7940e1..62251416847 100644 --- a/tests/wpt/web-platform-tests/fetch/api/response/response-clone.html +++ b/tests/wpt/web-platform-tests/fetch/api/response/response-clone.html @@ -70,13 +70,13 @@ return fetch('../resources/trickle.py?count=2&delay=100').then(function(res) { clone = res.clone(); response = res; - return clone.arrayBuffer(); + return clone.text(); }).then(function(r) { - assert_equals(r.byteLength, 26); + assert_equals(r.length, 26); result = r; - return response.arrayBuffer(); + return response.text(); }).then(function(r) { - assert_array_equals(r, result, "cloned responses should provide the same data"); + assert_equals(r, result, "cloned responses should provide the same data"); }); }, 'Cloned responses should provide the same data'); diff --git a/tests/wpt/web-platform-tests/html/editing/editing-0/contenteditable/user-interaction-editing-contenteditable.html b/tests/wpt/web-platform-tests/html/editing/editing-0/contenteditable/user-interaction-editing-contenteditable.html index 9ef867b2d3f..0a12b8c4f51 100644 --- a/tests/wpt/web-platform-tests/html/editing/editing-0/contenteditable/user-interaction-editing-contenteditable.html +++ b/tests/wpt/web-platform-tests/html/editing/editing-0/contenteditable/user-interaction-editing-contenteditable.html @@ -1,54 +1,228 @@ - - Editing: contentEditable attribute test - - - - -
- - - - + + Editing: contentEditable attribute test + + + + +
+ + + + diff --git a/tests/wpt/web-platform-tests/html/semantics/forms/form-submission-0/form-double-submit-multiple-targets.html b/tests/wpt/web-platform-tests/html/semantics/forms/form-submission-0/form-double-submit-multiple-targets.html new file mode 100644 index 00000000000..2b5a589b534 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/forms/form-submission-0/form-double-submit-multiple-targets.html @@ -0,0 +1,37 @@ + + + + + + + + + +
+ + + + + diff --git a/tests/wpt/web-platform-tests/html/semantics/forms/form-submission-0/jsurl-navigation-then-form-submit.html b/tests/wpt/web-platform-tests/html/semantics/forms/form-submission-0/jsurl-navigation-then-form-submit.html new file mode 100644 index 00000000000..93a4ea6004a --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/forms/form-submission-0/jsurl-navigation-then-form-submit.html @@ -0,0 +1,30 @@ + + + + + + + + + + diff --git a/tests/wpt/web-platform-tests/html/semantics/forms/the-select-element/reset-algorithm-rendering-ref.html b/tests/wpt/web-platform-tests/html/semantics/forms/the-select-element/reset-algorithm-rendering-ref.html new file mode 100644 index 00000000000..acf192d1d55 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/forms/the-select-element/reset-algorithm-rendering-ref.html @@ -0,0 +1,21 @@ + + + +
+ + + + + +
+ + diff --git a/tests/wpt/web-platform-tests/html/semantics/forms/the-select-element/reset-algorithm-rendering.html b/tests/wpt/web-platform-tests/html/semantics/forms/the-select-element/reset-algorithm-rendering.html new file mode 100644 index 00000000000..67da173ff2e --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/forms/the-select-element/reset-algorithm-rendering.html @@ -0,0 +1,39 @@ + + +Invalidation test on resetting <select> + + + + + +
+ + + + + +
+ + + + + diff --git a/tests/wpt/web-platform-tests/pointerevents/compat/pointerevent_mouseevent_key_pressed.html b/tests/wpt/web-platform-tests/pointerevents/compat/pointerevent_mouseevent_key_pressed.html new file mode 100644 index 00000000000..ea45adee820 --- /dev/null +++ b/tests/wpt/web-platform-tests/pointerevents/compat/pointerevent_mouseevent_key_pressed.html @@ -0,0 +1,60 @@ + + + + + Mouse events with keys pressed + + + + + + + + + + + +

Test Description: Tests that the mouse events with some keys pressed. +
    +
  1. Press Alt, Control, Meta, Shift keys and move the mouse
  2. +
+

+ + diff --git a/tests/wpt/web-platform-tests/pointerevents/pointerevent_support.js b/tests/wpt/web-platform-tests/pointerevents/pointerevent_support.js index 8dbedf21686..7f291d7609a 100644 --- a/tests/wpt/web-platform-tests/pointerevents/pointerevent_support.js +++ b/tests/wpt/web-platform-tests/pointerevents/pointerevent_support.js @@ -392,3 +392,13 @@ function resolveWhen(condition) { tick(); }); } + +// Returns a promise that only gets resolved after n animation frames +function waitForAnimationFrames(n){ + let p = 0; + function next(){ + p++; + return p === n; + } + return resolveWhen(next); +} diff --git a/tests/wpt/web-platform-tests/resources/idlharness.js b/tests/wpt/web-platform-tests/resources/idlharness.js index 02233ee0d33..cb66fcaa98c 100644 --- a/tests/wpt/web-platform-tests/resources/idlharness.js +++ b/tests/wpt/web-platform-tests/resources/idlharness.js @@ -1209,29 +1209,22 @@ IdlArray.prototype.assert_type_is = function(value, type) assert_regexp_match(value, /^([\x00-\ud7ff\ue000-\uffff]|[\ud800-\udbff][\udc00-\udfff])*$/); return; - case "Int8Array": - case "Int16Array": - case "Int32Array": - case "Uint8Array": - case "Uint16Array": - case "Uint32Array": - case "Uint8ClampedArray": - case "Float32Array": - case "Float64Array": - case "ArrayBuffer": - case "DataView": - case "Function": - assert_true(value instanceof self[type], "wrong type: not a " + type); - return; - case "object": assert_in_array(typeof value, ["object", "function"], "wrong type: not object or function"); return; } + // This is a catch-all for any IDL type name which follows JS class + // semantics. This includes some non-interface IDL types (e.g. Int8Array, + // Function, ...), as well as any interface types that are not in the IDL + // that is fed to the harness. If an IDL type does not follow JS class + // semantics then it should go in the switch statement above. If an IDL + // type needs full checking, then the test should include it in the IDL it + // feeds to the harness. if (!(type in this.members)) { - throw new IdlHarnessError("Unrecognized type " + type); + assert_true(value instanceof self[type], "wrong type: not a " + type); + return; } if (this.members[type] instanceof IdlInterface) diff --git a/tests/wpt/web-platform-tests/scroll-animations/layout-changes-on-percentage-based-timeline.html b/tests/wpt/web-platform-tests/scroll-animations/layout-changes-on-percentage-based-timeline.html new file mode 100644 index 00000000000..82b67018622 --- /dev/null +++ b/tests/wpt/web-platform-tests/scroll-animations/layout-changes-on-percentage-based-timeline.html @@ -0,0 +1,84 @@ + +Layout changes on percentage-based scroll timeline + + + + + + + + + +
+
+
+
+ +
+ + \ No newline at end of file diff --git a/tests/wpt/web-platform-tests/tools/ci/azure/safari-technology-preview.rb b/tests/wpt/web-platform-tests/tools/ci/azure/safari-technology-preview.rb index eae03474a49..c7d83bab9be 100644 --- a/tests/wpt/web-platform-tests/tools/ci/azure/safari-technology-preview.rb +++ b/tests/wpt/web-platform-tests/tools/ci/azure/safari-technology-preview.rb @@ -1,10 +1,10 @@ cask 'safari-technology-preview' do if MacOS.version <= :mojave - version '106,001-05966-20200513-86571be6-878e-411b-a5b9-65a971573fae' - sha256 '8518c8917a9172aeb75deeb61060d353229760fd54dc85bd38a0897cc1d12105' + version '107,001-09573-20200527-5319cd41-1eb4-412a-817a-bf376957b539' + sha256 'c06f7ecd3fb310bc59e06010d1f8c6dbdb57dbc671070fa0d9fc69c295eb0190' else - version '106,001-05890-20200513-321a69b4-de58-440e-8182-8ac03d65f6ce' - sha256 'f3c073d9b60ff6d11f82abbc6cc131e5913e6d0f2a11f0968ae77db1b51e1e35' + version '107,001-09514-20200527-05f7a42c-d9a0-4a60-ba12-97f2145db993' + sha256 '50baba474a0f0c773e4907ba8b06c80171de79f15b2ee653301cfe8230d0a0ef' end url "https://secure-appldnld.apple.com/STP/#{version.after_comma}/SafariTechnologyPreview.dmg" diff --git a/tests/wpt/web-platform-tests/tools/quic/requirements.txt b/tests/wpt/web-platform-tests/tools/quic/requirements.txt index 165260c78f7..c66414cb751 100644 --- a/tests/wpt/web-platform-tests/tools/quic/requirements.txt +++ b/tests/wpt/web-platform-tests/tools/quic/requirements.txt @@ -1 +1 @@ -aioquic==0.8.7 +aioquic==0.8.8 diff --git a/tests/wpt/web-platform-tests/tools/third_party/aioquic/.github/workflows/tests.yml b/tests/wpt/web-platform-tests/tools/third_party/aioquic/.github/workflows/tests.yml index d19b21d7458..c244de93569 100644 --- a/tests/wpt/web-platform-tests/tools/third_party/aioquic/.github/workflows/tests.yml +++ b/tests/wpt/web-platform-tests/tools/third_party/aioquic/.github/workflows/tests.yml @@ -47,7 +47,7 @@ jobs: echo "::set-env name=LINK::/LIBPATH:C:\Progra~1\OpenSSL-Win64\lib" - name: Run tests run: | - pip install -U pip setuptools wheel + python -m pip install -U pip setuptools wheel pip install coverage pip install . coverage run -m unittest discover -v @@ -84,20 +84,10 @@ jobs: - uses: actions/setup-python@v1 with: python-version: 3.7 - - name: Install nasm - if: matrix.os == 'windows-latest' - run: choco install -y nasm - - name: Install nmake - if: matrix.os == 'windows-latest' - run: | - & "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vs_installer.exe" modify ` - --installPath "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise" ` - --add Microsoft.VisualStudio.Component.VC.Tools.x86.x64 --passive --norestart - shell: powershell - name: Build wheels env: - CIBW_BEFORE_BUILD: scripts/build-openssl /tmp/vendor - CIBW_BEFORE_BUILD_WINDOWS: scripts\build-openssl.bat C:\cibw\vendor + CIBW_BEFORE_BUILD: python scripts/fetch-vendor /tmp/vendor + CIBW_BEFORE_BUILD_WINDOWS: python scripts\fetch-vendor C:\cibw\vendor CIBW_ENVIRONMENT: AIOQUIC_SKIP_TESTS=ipv6,loss CFLAGS=-I/tmp/vendor/include LDFLAGS=-L/tmp/vendor/lib CIBW_ENVIRONMENT_WINDOWS: AIOQUIC_SKIP_TESTS=ipv6,loss CL="/IC:\cibw\vendor\include" LINK="/LIBPATH:C:\cibw\vendor\lib" CIBW_SKIP: cp27-* cp33-* cp34-* cp35-* pp27-* diff --git a/tests/wpt/web-platform-tests/tools/third_party/aioquic/README.rst b/tests/wpt/web-platform-tests/tools/third_party/aioquic/README.rst index 2322042c24d..20d502a7700 100644 --- a/tests/wpt/web-platform-tests/tools/third_party/aioquic/README.rst +++ b/tests/wpt/web-platform-tests/tools/third_party/aioquic/README.rst @@ -115,42 +115,9 @@ You will need to set some environment variables to link against OpenSSL: Running the examples -------------------- -After checking out the code using git you can run: +`aioquic` comes with a number of examples illustrating various QUIC usecases. -.. code-block:: console - - $ pip install -e . - $ pip install aiofiles asgiref httpbin starlette wsproto - -HTTP/3 server -............. - -You can run the example server, which handles both HTTP/0.9 and HTTP/3: - -.. code-block:: console - - $ python examples/http3_server.py --certificate tests/ssl_cert.pem --private-key tests/ssl_key.pem - -HTTP/3 client -............. - -You can run the example client to perform an HTTP/3 request: - -.. code-block:: console - - $ python examples/http3_client.py --ca-certs tests/pycacert.pem https://localhost:4433/ - -Alternatively you can perform an HTTP/0.9 request: - -.. code-block:: console - - $ python examples/http3_client.py --ca-certs tests/pycacert.pem --legacy-http https://localhost:4433/ - -You can also open a WebSocket over HTTP/3: - -.. code-block:: console - - $ python examples/http3_client.py --ca-certs tests/pycacert.pem wss://localhost:4433/ws +You can browse these examples here: https://github.com/aiortc/aioquic/tree/master/examples License ------- diff --git a/tests/wpt/web-platform-tests/tools/third_party/aioquic/examples/README.rst b/tests/wpt/web-platform-tests/tools/third_party/aioquic/examples/README.rst new file mode 100644 index 00000000000..5d4af57d514 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/aioquic/examples/README.rst @@ -0,0 +1,62 @@ +Examples +======== + +After checking out the code using git you can run: + +.. code-block:: console + + $ pip install -e . + $ pip install aiofiles asgiref dnslib httpbin starlette wsproto + + +HTTP/3 +------ + +HTTP/3 server +............. + +You can run the example server, which handles both HTTP/0.9 and HTTP/3: + +.. code-block:: console + + $ python examples/http3_server.py --certificate tests/ssl_cert.pem --private-key tests/ssl_key.pem + +HTTP/3 client +............. + +You can run the example client to perform an HTTP/3 request: + +.. code-block:: console + + $ python examples/http3_client.py --ca-certs tests/pycacert.pem https://localhost:4433/ + +Alternatively you can perform an HTTP/0.9 request: + +.. code-block:: console + + $ python examples/http3_client.py --ca-certs tests/pycacert.pem --legacy-http https://localhost:4433/ + +You can also open a WebSocket over HTTP/3: + +.. code-block:: console + + $ python examples/http3_client.py --ca-certs tests/pycacert.pem wss://localhost:4433/ws + + +DNS over QUIC +------------- + +By default the server will use the `Google Public DNS`_ service, you can +override this with the ``--resolver`` argument. + +.. code-block:: console + + $ python examples/doq_server.py --certificate tests/ssl_cert.pem --private-key tests/ssl_key.pem + +You can then run the client with a specific query: + +.. code-block:: console + + $ python examples/doq_client.py --ca-certs tests/pycacert.pem --dns_type "A" --query "quic.aiortc.org" --port 4784 + +.. _Google Public DNS: https://developers.google.com/speed/public-dns diff --git a/tests/wpt/web-platform-tests/tools/third_party/aioquic/examples/doq_client.py b/tests/wpt/web-platform-tests/tools/third_party/aioquic/examples/doq_client.py new file mode 100644 index 00000000000..06c1a44f028 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/aioquic/examples/doq_client.py @@ -0,0 +1,162 @@ +import argparse +import asyncio +import json +import logging +import pickle +import ssl +from typing import Optional, cast + +from dnslib.dns import QTYPE, DNSQuestion, DNSRecord + +from aioquic.asyncio.client import connect +from aioquic.asyncio.protocol import QuicConnectionProtocol +from aioquic.quic.configuration import QuicConfiguration +from aioquic.quic.events import QuicEvent, StreamDataReceived +from aioquic.quic.logger import QuicLogger + +logger = logging.getLogger("client") + + +class DoQClient(QuicConnectionProtocol): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._ack_waiter: Optional[asyncio.Future[None]] = None + + async def query(self, query_type: str, dns_query: str) -> None: + query = DNSRecord(q=DNSQuestion(dns_query, getattr(QTYPE, query_type))) + stream_id = self._quic.get_next_available_stream_id() + logger.debug(f"Stream ID: {stream_id}") + end_stream = False + self._quic.send_stream_data(stream_id, bytes(query.pack()), end_stream) + waiter = self._loop.create_future() + self._ack_waiter = waiter + self.transmit() + + return await asyncio.shield(waiter) + + def quic_event_received(self, event: QuicEvent) -> None: + if self._ack_waiter is not None: + if isinstance(event, StreamDataReceived): + answer = DNSRecord.parse(event.data) + logger.info(answer) + waiter = self._ack_waiter + self._ack_waiter = None + waiter.set_result(None) + + +def save_session_ticket(ticket): + """ + Callback which is invoked by the TLS engine when a new session ticket + is received. + """ + logger.info("New session ticket received") + if args.session_ticket: + with open(args.session_ticket, "wb") as fp: + pickle.dump(ticket, fp) + + +async def run( + configuration: QuicConfiguration, + host: str, + port: int, + query_type: str, + dns_query: str, +) -> None: + logger.debug(f"Connecting to {host}:{port}") + async with connect( + host, + port, + configuration=configuration, + session_ticket_handler=save_session_ticket, + create_protocol=DoQClient, + ) as client: + client = cast(DoQClient, client) + logger.debug("Sending DNS query") + await client.query(query_type, dns_query) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="DNS over QUIC client") + parser.add_argument("-t", "--type", type=str, help="Type of record to ") + parser.add_argument( + "--host", + type=str, + default="localhost", + help="The remote peer's host name or IP address", + ) + parser.add_argument( + "--port", type=int, default=784, help="The remote peer's port number" + ) + parser.add_argument( + "-k", + "--insecure", + action="store_true", + help="do not validate server certificate", + ) + parser.add_argument( + "--ca-certs", type=str, help="load CA certificates from the specified file" + ) + parser.add_argument("--dns_type", help="The DNS query type to send") + parser.add_argument("--query", help="Domain to query") + parser.add_argument( + "-q", "--quic-log", type=str, help="log QUIC events to a file in QLOG format" + ) + parser.add_argument( + "-l", + "--secrets-log", + type=str, + help="log secrets to a file, for use with Wireshark", + ) + parser.add_argument( + "-s", + "--session-ticket", + type=str, + help="read and write session ticket from the specified file", + ) + parser.add_argument( + "-v", "--verbose", action="store_true", help="increase logging verbosity" + ) + + args = parser.parse_args() + + logging.basicConfig( + format="%(asctime)s %(levelname)s %(name)s %(message)s", + level=logging.DEBUG if args.verbose else logging.INFO, + ) + + configuration = QuicConfiguration( + alpn_protocols=["dq"], is_client=True, max_datagram_frame_size=65536 + ) + if args.ca_certs: + configuration.load_verify_locations(args.ca_certs) + if args.insecure: + configuration.verify_mode = ssl.CERT_NONE + if args.quic_log: + configuration.quic_logger = QuicLogger() + if args.secrets_log: + configuration.secrets_log_file = open(args.secrets_log, "a") + if args.session_ticket: + try: + with open(args.session_ticket, "rb") as fp: + configuration.session_ticket = pickle.load(fp) + except FileNotFoundError: + logger.debug(f"Unable to read {args.session_ticket}") + pass + else: + logger.debug("No session ticket defined...") + + loop = asyncio.get_event_loop() + try: + loop.run_until_complete( + run( + configuration=configuration, + host=args.host, + port=args.port, + query_type=args.dns_type, + dns_query=args.query, + ) + ) + finally: + if configuration.quic_logger is not None: + with open(args.quic_log, "w") as logger_fp: + json.dump(configuration.quic_logger.to_dict(), logger_fp, indent=4) diff --git a/tests/wpt/web-platform-tests/tools/third_party/aioquic/examples/doq_server.py b/tests/wpt/web-platform-tests/tools/third_party/aioquic/examples/doq_server.py new file mode 100644 index 00000000000..f3347fe6c18 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/aioquic/examples/doq_server.py @@ -0,0 +1,167 @@ +import argparse +import asyncio +import json +import logging +from typing import Dict, Optional + +from dnslib.dns import DNSRecord + +from aioquic.asyncio import QuicConnectionProtocol, serve +from aioquic.quic.configuration import QuicConfiguration +from aioquic.quic.connection import QuicConnection +from aioquic.quic.events import ProtocolNegotiated, QuicEvent, StreamDataReceived +from aioquic.quic.logger import QuicLogger +from aioquic.tls import SessionTicket + +try: + import uvloop +except ImportError: + uvloop = None + + +class DnsConnection: + def __init__(self, quic: QuicConnection): + self._quic = quic + + def do_query(self, payload) -> bytes: + q = DNSRecord.parse(payload) + return q.send(self.resolver(), 53) + + def resolver(self) -> str: + return args.resolver + + def handle_event(self, event: QuicEvent) -> None: + if isinstance(event, StreamDataReceived): + data = self.do_query(event.data) + end_stream = False + self._quic.send_stream_data(event.stream_id, data, end_stream) + + +class DnsServerProtocol(QuicConnectionProtocol): + + # -00 specifies 'dq', 'doq', and 'doq-h00' (the latter obviously tying to + # the version of the draft it matches). This is confusing, so we'll just + # support them all, until future drafts define conflicting behaviour. + SUPPORTED_ALPNS = ["dq", "doq", "doq-h00"] + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._dns: Optional[DnsConnection] = None + + def quic_event_received(self, event: QuicEvent): + if isinstance(event, ProtocolNegotiated): + if event.alpn_protocol in DnsServerProtocol.SUPPORTED_ALPNS: + self._dns = DnsConnection(self._quic) + if self._dns is not None: + self._dns.handle_event(event) + + +class SessionTicketStore: + """ + Simple in-memory store for session tickets. + """ + + def __init__(self) -> None: + self.tickets: Dict[bytes, SessionTicket] = {} + + def add(self, ticket: SessionTicket) -> None: + self.tickets[ticket.ticket] = ticket + + def pop(self, label: bytes) -> Optional[SessionTicket]: + return self.tickets.pop(label, None) + + +if __name__ == "__main__": + + parser = argparse.ArgumentParser(description="DNS over QUIC server") + parser.add_argument( + "--host", + type=str, + default="::", + help="listen on the specified address (defaults to ::)", + ) + parser.add_argument( + "--port", + type=int, + default=4784, + help="listen on the specified port (defaults to 4784)", + ) + parser.add_argument( + "-k", + "--private-key", + type=str, + required=True, + help="load the TLS private key from the specified file", + ) + parser.add_argument( + "-c", + "--certificate", + type=str, + required=True, + help="load the TLS certificate from the specified file", + ) + parser.add_argument( + "-r", + "--resolver", + type=str, + default="8.8.8.8", + help="Upstream Classic DNS resolver to use", + ) + parser.add_argument( + "-s", + "--stateless-retry", + action="store_true", + help="send a stateless retry for new connections", + ) + parser.add_argument( + "-q", "--quic-log", type=str, help="log QUIC events to a file in QLOG format" + ) + parser.add_argument( + "-v", "--verbose", action="store_true", help="increase logging verbosity" + ) + + args = parser.parse_args() + + logging.basicConfig( + format="%(asctime)s %(levelname)s %(name)s %(message)s", + level=logging.DEBUG if args.verbose else logging.INFO, + ) + + if args.quic_log: + quic_logger = QuicLogger() + else: + quic_logger = None + + configuration = QuicConfiguration( + alpn_protocols=["dq"], + is_client=False, + max_datagram_frame_size=65536, + quic_logger=quic_logger, + ) + + configuration.load_cert_chain(args.certificate, args.private_key) + + ticket_store = SessionTicketStore() + + if uvloop is not None: + uvloop.install() + loop = asyncio.get_event_loop() + loop.run_until_complete( + serve( + args.host, + args.port, + configuration=configuration, + create_protocol=DnsServerProtocol, + session_ticket_fetcher=ticket_store.pop, + session_ticket_handler=ticket_store.add, + stateless_retry=args.stateless_retry, + ) + ) + try: + loop.run_forever() + except KeyboardInterrupt: + pass + finally: + if configuration.quic_logger is not None: + with open(args.quic_log, "w") as logger_fp: + json.dump(configuration.quic_logger.to_dict(), logger_fp, indent=4) diff --git a/tests/wpt/web-platform-tests/tools/third_party/aioquic/scripts/build-openssl b/tests/wpt/web-platform-tests/tools/third_party/aioquic/scripts/build-openssl deleted file mode 100755 index 94ded72c172..00000000000 --- a/tests/wpt/web-platform-tests/tools/third_party/aioquic/scripts/build-openssl +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/sh - -set -e - -destdir=$1 -cachedir=$1.$PYTHON_ARCH - -for d in openssl $destdir; do - if [ -e $d ]; then - rm -rf $d - fi -done - -if [ ! -e $cachedir ]; then - # build openssl - mkdir openssl - curl -L https://www.openssl.org/source/openssl-1.1.1f.tar.gz | tar xz -C openssl --strip-components 1 - cd openssl - - ./config no-comp no-shared no-tests - make - - mkdir $cachedir - mkdir $cachedir/lib - cp -R include $cachedir - cp libcrypto.a libssl.a $cachedir/lib -fi - -cp -R $cachedir $destdir diff --git a/tests/wpt/web-platform-tests/tools/third_party/aioquic/scripts/build-openssl.bat b/tests/wpt/web-platform-tests/tools/third_party/aioquic/scripts/build-openssl.bat deleted file mode 100644 index 610079ddf83..00000000000 --- a/tests/wpt/web-platform-tests/tools/third_party/aioquic/scripts/build-openssl.bat +++ /dev/null @@ -1,39 +0,0 @@ -set destdir=%1 -set cachedir=%1.%PYTHON_ARCH% - -for %%d in (openssl %destdir%) do ( - if exist %%d ( - rmdir /s /q %%d - ) -) - -if %PYTHON_ARCH% == 64 ( - set OPENSSL_CONFIG=VC-WIN64A - set VC_ARCH=x64 -) else ( - set OPENSSL_CONFIG=VC-WIN32 - set VC_ARCH=x86 -) - -call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" %VC_ARCH% -SET PATH=%PATH%;C:\Program Files\NASM - -if not exist %cachedir% ( - mkdir openssl - curl -L https://www.openssl.org/source/openssl-1.1.1f.tar.gz -o openssl.tar.gz - tar xzf openssl.tar.gz -C openssl --strip-components 1 - cd openssl - - perl Configure no-comp no-shared no-tests %OPENSSL_CONFIG% - nmake - - mkdir %cachedir% - mkdir %cachedir%\include - mkdir %cachedir%\lib - xcopy include %cachedir%\include\ /E - copy libcrypto.lib %cachedir%\lib\ - copy libssl.lib %cachedir%\lib\ -) - -mkdir %destdir% -xcopy %cachedir% %destdir% /E diff --git a/tests/wpt/web-platform-tests/tools/third_party/aioquic/scripts/fetch-vendor b/tests/wpt/web-platform-tests/tools/third_party/aioquic/scripts/fetch-vendor new file mode 100755 index 00000000000..a06d6237147 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/aioquic/scripts/fetch-vendor @@ -0,0 +1,61 @@ +#!/usr/bin/env python + +import argparse +import logging +import json +import os +import shutil +import struct +import subprocess +import sys + + +def get_platform(): + if sys.platform == "linux": + return "manylinux_%s" % os.uname().machine + elif sys.platform == "darwin": + return "macosx_%s" % os.uname().machine + elif sys.platform == "win32": + return "win%s" % (struct.calcsize("P") * 8) + else: + raise Exception("Unsupported platfom %s" % sys.platform) + + +parser = argparse.ArgumentParser(description="Fetch and extract tarballs") +parser.add_argument("destination_dir") +parser.add_argument("--cache-dir", default="tarballs") +parser.add_argument("--config-file", default=__file__ + ".json") +args = parser.parse_args() +logging.basicConfig(level=logging.INFO) + +# work around buggy 'tar' executable on Windows +if sys.platform == "win32": + os.environ["PATH"] = "C:\\Program Files\\Git\\usr\\bin;" + os.environ["PATH"] + +# read config file +with open(args.config_file, "r") as fp: + config = json.load(fp) + +# create fresh destination directory +logging.info("Creating directory %s" % args.destination_dir) +if os.path.exists(args.destination_dir): + shutil.rmtree(args.destination_dir) +os.mkdir(args.destination_dir) + +for url_template in config["urls"]: + tarball_url = url_template.replace("{platform}", get_platform()) + + # download tarball + tarball_name = tarball_url.split("/")[-1] + tarball_file = os.path.join(args.cache_dir, tarball_name) + if not os.path.exists(tarball_file): + logging.info("Downloading %s" % tarball_url) + if not os.path.exists(args.cache_dir): + os.mkdir(args.cache_dir) + subprocess.check_call( + ["curl", "--location", "--output", tarball_file, "--silent", tarball_url] + ) + + # extract tarball + logging.info("Extracting %s" % tarball_name) + subprocess.check_call(["tar", "-C", args.destination_dir, "-xf", tarball_file]) diff --git a/tests/wpt/web-platform-tests/tools/third_party/aioquic/scripts/fetch-vendor.json b/tests/wpt/web-platform-tests/tools/third_party/aioquic/scripts/fetch-vendor.json new file mode 100644 index 00000000000..f280235beb0 --- /dev/null +++ b/tests/wpt/web-platform-tests/tools/third_party/aioquic/scripts/fetch-vendor.json @@ -0,0 +1,3 @@ +{ + "urls": ["https://github.com/aiortc/aioquic-openssl/releases/download/1.1.1f-1/openssl-{platform}.tar.bz2"] +} diff --git a/tests/wpt/web-platform-tests/tools/third_party/aioquic/src/aioquic/about.py b/tests/wpt/web-platform-tests/tools/third_party/aioquic/src/aioquic/about.py index 82cd8f33d65..98eed8d6bcc 100644 --- a/tests/wpt/web-platform-tests/tools/third_party/aioquic/src/aioquic/about.py +++ b/tests/wpt/web-platform-tests/tools/third_party/aioquic/src/aioquic/about.py @@ -4,4 +4,4 @@ __license__ = "BSD" __summary__ = "An implementation of QUIC and HTTP/3" __title__ = "aioquic" __uri__ = "https://github.com/aiortc/aioquic" -__version__ = "0.8.7" +__version__ = "0.8.8" diff --git a/tests/wpt/web-platform-tests/tools/third_party/aioquic/src/aioquic/quic/connection.py b/tests/wpt/web-platform-tests/tools/third_party/aioquic/src/aioquic/quic/connection.py index 461df4fc191..0e1372cc08b 100644 --- a/tests/wpt/web-platform-tests/tools/third_party/aioquic/src/aioquic/quic/connection.py +++ b/tests/wpt/web-platform-tests/tools/third_party/aioquic/src/aioquic/quic/connection.py @@ -46,6 +46,7 @@ from .stream import QuicStream logger = logging.getLogger("quic") +CRYPTO_BUFFER_SIZE = 16384 EPOCH_SHORTCUTS = { "I": tls.Epoch.INITIAL, "H": tls.Epoch.HANDSHAKE, @@ -1195,9 +1196,9 @@ class QuicConnection: tls.Epoch.ONE_RTT: CryptoPair(), } self._crypto_buffers = { - tls.Epoch.INITIAL: Buffer(capacity=4096), - tls.Epoch.HANDSHAKE: Buffer(capacity=4096), - tls.Epoch.ONE_RTT: Buffer(capacity=4096), + tls.Epoch.INITIAL: Buffer(capacity=CRYPTO_BUFFER_SIZE), + tls.Epoch.HANDSHAKE: Buffer(capacity=CRYPTO_BUFFER_SIZE), + tls.Epoch.ONE_RTT: Buffer(capacity=CRYPTO_BUFFER_SIZE), } self._crypto_streams = { tls.Epoch.INITIAL: QuicStream(), diff --git a/tests/wpt/web-platform-tests/tools/third_party/aioquic/src/aioquic/tls.py b/tests/wpt/web-platform-tests/tools/third_party/aioquic/src/aioquic/tls.py index 30b69ff2d32..94b10cbba5d 100644 --- a/tests/wpt/web-platform-tests/tools/third_party/aioquic/src/aioquic/tls.py +++ b/tests/wpt/web-platform-tests/tools/third_party/aioquic/src/aioquic/tls.py @@ -550,9 +550,9 @@ class OfferedPsks: @dataclass class ClientHello: random: bytes - session_id: bytes + legacy_session_id: bytes cipher_suites: List[int] - compression_methods: List[int] + legacy_compression_methods: List[int] # extensions alpn_protocols: Optional[List[str]] = None @@ -572,13 +572,12 @@ def pull_client_hello(buf: Buffer) -> ClientHello: assert buf.pull_uint8() == HandshakeType.CLIENT_HELLO with pull_block(buf, 3): assert buf.pull_uint16() == TLS_VERSION_1_2 - client_random = buf.pull_bytes(32) hello = ClientHello( - random=client_random, - session_id=pull_opaque(buf, 1), + random=buf.pull_bytes(32), + legacy_session_id=pull_opaque(buf, 1), cipher_suites=pull_list(buf, 2, buf.pull_uint16), - compression_methods=pull_list(buf, 1, buf.pull_uint8), + legacy_compression_methods=pull_list(buf, 1, buf.pull_uint8), ) # extensions @@ -632,9 +631,9 @@ def push_client_hello(buf: Buffer, hello: ClientHello) -> None: with push_block(buf, 3): buf.push_uint16(TLS_VERSION_1_2) buf.push_bytes(hello.random) - push_opaque(buf, 1, hello.session_id) + push_opaque(buf, 1, hello.legacy_session_id) push_list(buf, 2, buf.push_uint16, hello.cipher_suites) - push_list(buf, 1, buf.push_uint8, hello.compression_methods) + push_list(buf, 1, buf.push_uint8, hello.legacy_compression_methods) # extensions with push_block(buf, 2): @@ -694,7 +693,7 @@ def push_client_hello(buf: Buffer, hello: ClientHello) -> None: @dataclass class ServerHello: random: bytes - session_id: bytes + legacy_session_id: bytes cipher_suite: int compression_method: int @@ -709,11 +708,10 @@ def pull_server_hello(buf: Buffer) -> ServerHello: assert buf.pull_uint8() == HandshakeType.SERVER_HELLO with pull_block(buf, 3): assert buf.pull_uint16() == TLS_VERSION_1_2 - server_random = buf.pull_bytes(32) hello = ServerHello( - random=server_random, - session_id=pull_opaque(buf, 1), + random=buf.pull_bytes(32), + legacy_session_id=pull_opaque(buf, 1), cipher_suite=buf.pull_uint16(), compression_method=buf.pull_uint8(), ) @@ -744,7 +742,7 @@ def push_server_hello(buf: Buffer, hello: ServerHello) -> None: buf.push_uint16(TLS_VERSION_1_2) buf.push_bytes(hello.random) - push_opaque(buf, 1, hello.session_id) + push_opaque(buf, 1, hello.legacy_session_id) buf.push_uint16(hello.cipher_suite) buf.push_uint8(hello.compression_method) @@ -1216,7 +1214,7 @@ class Context: CipherSuite.AES_128_GCM_SHA256, CipherSuite.CHACHA20_POLY1305_SHA256, ] - self._compression_methods: List[int] = [CompressionMethod.NULL] + self._legacy_compression_methods: List[int] = [CompressionMethod.NULL] self._psk_key_exchange_modes: List[int] = [PskKeyExchangeMode.PSK_DHE_KE] self._signature_algorithms: List[int] = [ SignatureAlgorithm.RSA_PSS_RSAE_SHA256, @@ -1253,11 +1251,11 @@ class Context: if is_client: self.client_random = os.urandom(32) - self.session_id = os.urandom(32) + self.legacy_session_id = b"" self.state = State.CLIENT_HANDSHAKE_START else: self.client_random = None - self.session_id = None + self.legacy_session_id = None self.state = State.SERVER_EXPECT_CLIENT_HELLO @property @@ -1402,9 +1400,9 @@ class Context: hello = ClientHello( random=self.client_random, - session_id=self.session_id, + legacy_session_id=self.legacy_session_id, cipher_suites=[int(x) for x in self._cipher_suites], - compression_methods=self._compression_methods, + legacy_compression_methods=self._legacy_compression_methods, alpn_protocols=self._alpn_protocols, key_share=key_share, psk_key_exchange_modes=self._psk_key_exchange_modes @@ -1473,7 +1471,7 @@ class Context: [peer_hello.cipher_suite], AlertHandshakeFailure("Unsupported cipher suite"), ) - assert peer_hello.compression_method in self._compression_methods + assert peer_hello.compression_method in self._legacy_compression_methods assert peer_hello.supported_version in self._supported_versions # select key schedule @@ -1665,8 +1663,8 @@ class Context: AlertHandshakeFailure("No supported cipher suite"), ) compression_method = negotiate( - self._compression_methods, - peer_hello.compression_methods, + self._legacy_compression_methods, + peer_hello.legacy_compression_methods, AlertHandshakeFailure("No supported compression method"), ) psk_key_exchange_mode = negotiate( @@ -1695,7 +1693,7 @@ class Context: self.client_random = peer_hello.random self.server_random = os.urandom(32) - self.session_id = peer_hello.session_id + self.legacy_session_id = peer_hello.legacy_session_id self.received_extensions = peer_hello.other_extensions # select key schedule @@ -1787,7 +1785,7 @@ class Context: # send hello hello = ServerHello( random=self.server_random, - session_id=self.session_id, + legacy_session_id=self.legacy_session_id, cipher_suite=cipher_suite, compression_method=compression_method, key_share=encode_public_key(public_key), diff --git a/tests/wpt/web-platform-tests/tools/third_party/aioquic/tests/test_connection.py b/tests/wpt/web-platform-tests/tools/third_party/aioquic/tests/test_connection.py index af1a5cdc58f..427e1c04574 100644 --- a/tests/wpt/web-platform-tests/tools/third_party/aioquic/tests/test_connection.py +++ b/tests/wpt/web-platform-tests/tools/third_party/aioquic/tests/test_connection.py @@ -316,7 +316,7 @@ class QuicConnectionTest(TestCase): now = 1.1 server.receive_datagram(items[0][0], CLIENT_ADDR, now=now) items = server.datagrams_to_send(now=now) - self.assertEqual(datagram_sizes(items), [1280, 1062]) + self.assertEqual(datagram_sizes(items), [1280, 1030]) self.assertEqual(server.get_timer(), 2.1) self.assertEqual(len(server._loss.spaces[0].sent_packets), 1) self.assertEqual(len(server._loss.spaces[1].sent_packets), 2) @@ -377,7 +377,7 @@ class QuicConnectionTest(TestCase): now = 0.1 server.receive_datagram(items[0][0], CLIENT_ADDR, now=now) items = server.datagrams_to_send(now=now) - self.assertEqual(datagram_sizes(items), [1280, 1062]) + self.assertEqual(datagram_sizes(items), [1280, 1030]) self.assertEqual(server.get_timer(), 1.1) self.assertEqual(len(server._loss.spaces[0].sent_packets), 1) self.assertEqual(len(server._loss.spaces[1].sent_packets), 2) @@ -470,7 +470,7 @@ class QuicConnectionTest(TestCase): now = 0.1 server.receive_datagram(items[0][0], CLIENT_ADDR, now=now) items = server.datagrams_to_send(now=now) - self.assertEqual(datagram_sizes(items), [1280, 1062]) + self.assertEqual(datagram_sizes(items), [1280, 1030]) self.assertEqual(server.get_timer(), 1.1) self.assertEqual(len(server._loss.spaces[0].sent_packets), 1) self.assertEqual(len(server._loss.spaces[1].sent_packets), 2) diff --git a/tests/wpt/web-platform-tests/tools/third_party/aioquic/tests/test_tls.py b/tests/wpt/web-platform-tests/tools/third_party/aioquic/tests/test_tls.py index 72dd56deb8b..be8a470f74b 100644 --- a/tests/wpt/web-platform-tests/tools/third_party/aioquic/tests/test_tls.py +++ b/tests/wpt/web-platform-tests/tools/third_party/aioquic/tests/test_tls.py @@ -314,7 +314,7 @@ class ContextTest(TestCase): client.handle_message(b"", client_buf) self.assertEqual(client.state, State.CLIENT_EXPECT_SERVER_HELLO) server_input = merge_buffers(client_buf) - self.assertGreaterEqual(len(server_input), 213) + self.assertGreaterEqual(len(server_input), 181) self.assertLessEqual(len(server_input), 358) reset_buffers(client_buf) @@ -507,7 +507,7 @@ class ContextTest(TestCase): server.handle_message(server_input, server_buf) self.assertEqual(server.state, State.SERVER_EXPECT_FINISHED) client_input = merge_buffers(server_buf) - self.assertEqual(len(client_input), 307) + self.assertEqual(len(client_input), 275) reset_buffers(server_buf) # handle server hello, encrypted extensions, certificate, certificate verify, finished @@ -587,7 +587,7 @@ class ContextTest(TestCase): buf.seek(buf.tell() - 1) buf.push_uint8(1) client_input = merge_buffers(server_buf) - self.assertEqual(len(client_input), 307) + self.assertEqual(len(client_input), 275) reset_buffers(server_buf) # handle server hello and bomb @@ -613,7 +613,7 @@ class TlsTest(TestCase): ), ) self.assertEqual( - hello.session_id, + hello.legacy_session_id, binascii.unhexlify( "9aee82a2d186c1cb32a329d9dcfe004a1a438ad0485a53c6bfcf55c132a23235" ), @@ -626,7 +626,7 @@ class TlsTest(TestCase): tls.CipherSuite.CHACHA20_POLY1305_SHA256, ], ) - self.assertEqual(hello.compression_methods, [tls.CompressionMethod.NULL]) + self.assertEqual(hello.legacy_compression_methods, [tls.CompressionMethod.NULL]) # extensions self.assertEqual(hello.alpn_protocols, None) @@ -688,7 +688,7 @@ class TlsTest(TestCase): "ed575c6fbd599c4dfaabd003dca6e860ccdb0e1782c1af02e57bf27cb6479b76" ), ) - self.assertEqual(hello.session_id, b"") + self.assertEqual(hello.legacy_session_id, b"") self.assertEqual( hello.cipher_suites, [ @@ -698,7 +698,7 @@ class TlsTest(TestCase): tls.CipherSuite.EMPTY_RENEGOTIATION_INFO_SCSV, ], ) - self.assertEqual(hello.compression_methods, [tls.CompressionMethod.NULL]) + self.assertEqual(hello.legacy_compression_methods, [tls.CompressionMethod.NULL]) # extensions self.assertEqual(hello.alpn_protocols, ["h3-19"]) @@ -802,7 +802,7 @@ class TlsTest(TestCase): ), ) self.assertEqual( - hello.session_id, + hello.legacy_session_id, binascii.unhexlify( "26b19bdd30dbf751015a3a16e13bd59002dfe420b799d2a5cd5e11b8fa7bcb66" ), @@ -815,7 +815,7 @@ class TlsTest(TestCase): tls.CipherSuite.CHACHA20_POLY1305_SHA256, ], ) - self.assertEqual(hello.compression_methods, [tls.CompressionMethod.NULL]) + self.assertEqual(hello.legacy_compression_methods, [tls.CompressionMethod.NULL]) # extensions self.assertEqual(hello.alpn_protocols, None) @@ -876,7 +876,7 @@ class TlsTest(TestCase): random=binascii.unhexlify( "18b2b23bf3e44b5d52ccfe7aecbc5ff14eadc3d349fabf804d71f165ae76e7d5" ), - session_id=binascii.unhexlify( + legacy_session_id=binascii.unhexlify( "9aee82a2d186c1cb32a329d9dcfe004a1a438ad0485a53c6bfcf55c132a23235" ), cipher_suites=[ @@ -884,7 +884,7 @@ class TlsTest(TestCase): tls.CipherSuite.AES_128_GCM_SHA256, tls.CipherSuite.CHACHA20_POLY1305_SHA256, ], - compression_methods=[tls.CompressionMethod.NULL], + legacy_compression_methods=[tls.CompressionMethod.NULL], key_share=[ ( tls.Group.SECP256R1, @@ -933,7 +933,7 @@ class TlsTest(TestCase): ), ) self.assertEqual( - hello.session_id, + hello.legacy_session_id, binascii.unhexlify( "9aee82a2d186c1cb32a329d9dcfe004a1a438ad0485a53c6bfcf55c132a23235" ), @@ -966,7 +966,7 @@ class TlsTest(TestCase): ), ) self.assertEqual( - hello.session_id, + hello.legacy_session_id, binascii.unhexlify( "9483e7e895d0f4cec17086b0849601c0632662cd764e828f2f892f4c4b7771b0" ), @@ -1003,7 +1003,7 @@ class TlsTest(TestCase): random=binascii.unhexlify( "ada85271d19680c615ea7336519e3fdf6f1e26f3b1075ee1de96ffa8884e8280" ), - session_id=binascii.unhexlify( + legacy_session_id=binascii.unhexlify( "9aee82a2d186c1cb32a329d9dcfe004a1a438ad0485a53c6bfcf55c132a23235" ), cipher_suite=tls.CipherSuite.AES_256_GCM_SHA384, @@ -1031,7 +1031,7 @@ class TlsTest(TestCase): random=binascii.unhexlify( "ada85271d19680c615ea7336519e3fdf6f1e26f3b1075ee1de96ffa8884e8280" ), - session_id=binascii.unhexlify( + legacy_session_id=binascii.unhexlify( "9aee82a2d186c1cb32a329d9dcfe004a1a438ad0485a53c6bfcf55c132a23235" ), cipher_suite=tls.CipherSuite.AES_256_GCM_SHA384, diff --git a/tests/wpt/web-platform-tests/webrtc/RTCDataChannel-bufferedAmount.html b/tests/wpt/web-platform-tests/webrtc/RTCDataChannel-bufferedAmount.html index 89f6b1b4d7a..f663941162d 100644 --- a/tests/wpt/web-platform-tests/webrtc/RTCDataChannel-bufferedAmount.html +++ b/tests/wpt/web-platform-tests/webrtc/RTCDataChannel-bufferedAmount.html @@ -62,195 +62,163 @@ const unicodeBuffer = Uint8Array.of( 0xe4, 0xb8, 0x96, 0xe7, 0x95, 0x8c, 0xe4, 0xbd, 0xa0, 0xe5, 0xa5, 0xbd); -/* - Ensure .bufferedAmount is 0 initially for both sides. - */ -promise_test(async (t) => { - const pc1 = new RTCPeerConnection(); - const pc2 = new RTCPeerConnection(); - t.add_cleanup(() => pc1.close()); - t.add_cleanup(() => pc2.close()); +for (const options of [{}, {negotiated: true, id: 0}]) { + const mode = `${options.negotiated? "negotiated " : ""}datachannel`; - const [dc1, dc2] = await createDataChannelPair(pc1, pc2); + /* + Ensure .bufferedAmount is 0 initially for both sides. + */ + promise_test(async (t) => { + const [dc1, dc2] = await createDataChannelPair(t, options); - assert_equals(dc1.bufferedAmount, 0, 'Expect bufferedAmount to be 0'); - assert_equals(dc2.bufferedAmount, 0, 'Expect bufferedAmount to be 0'); -}, 'bufferedAmount initial value should be 0 for both peers'); + assert_equals(dc1.bufferedAmount, 0, 'Expect bufferedAmount to be 0'); + assert_equals(dc2.bufferedAmount, 0, 'Expect bufferedAmount to be 0'); + }, `${mode} bufferedAmount initial value should be 0 for both peers`); -/* - 6.2. send() - 3. Execute the sub step that corresponds to the type of the methods argument: + /* + 6.2. send() + 3. Execute the sub step that corresponds to the type of the methods argument: - string object - Let data be the object and increase the bufferedAmount attribute - by the number of bytes needed to express data as UTF-8. - */ -promise_test(async (t) => { - const pc1 = new RTCPeerConnection(); - const pc2 = new RTCPeerConnection(); - t.add_cleanup(() => pc1.close()); - t.add_cleanup(() => pc2.close()); + string object + Let data be the object and increase the bufferedAmount attribute + by the number of bytes needed to express data as UTF-8. + */ + promise_test(async (t) => { + const [dc1, dc2] = await createDataChannelPair(t, options); - const [dc1, dc2] = await createDataChannelPair(pc1, pc2); + dc1.send(unicodeString); + assert_equals(dc1.bufferedAmount, unicodeBuffer.byteLength, + 'Expect bufferedAmount to be the byte length of the unicode string'); - dc1.send(unicodeString); - assert_equals(dc1.bufferedAmount, unicodeBuffer.byteLength, - 'Expect bufferedAmount to be the byte length of the unicode string'); + await awaitMessage(dc2); + assert_equals(dc1.bufferedAmount, 0, + 'Expect sender bufferedAmount to be reduced after message is sent'); + }, `${mode} bufferedAmount should increase to byte length of encoded` + + `unicode string sent`); - await awaitMessage(dc2); - assert_equals(dc1.bufferedAmount, 0, - 'Expect sender bufferedAmount to be reduced after message is sent'); -}, 'bufferedAmount should increase to byte length of encoded unicode string sent'); + /* + 6.2. send() + 3. Execute the sub step that corresponds to the type of the methods argument: + ArrayBuffer object + Let data be the data stored in the buffer described by the ArrayBuffer + object and increase the bufferedAmount attribute by the length of the + ArrayBuffer in bytes. + */ + promise_test(async (t) => { + const [dc1, dc2] = await createDataChannelPair(t, options); -/* - 6.2. send() - 3. Execute the sub step that corresponds to the type of the methods argument: - ArrayBuffer object - Let data be the data stored in the buffer described by the ArrayBuffer - object and increase the bufferedAmount attribute by the length of the - ArrayBuffer in bytes. - */ -promise_test(async (t) => { - const pc1 = new RTCPeerConnection(); - const pc2 = new RTCPeerConnection(); - t.add_cleanup(() => pc1.close()); - t.add_cleanup(() => pc2.close()); + dc1.send(helloBuffer.buffer); + assert_equals(dc1.bufferedAmount, helloBuffer.byteLength, + 'Expect bufferedAmount to increase to byte length of sent buffer'); - const [dc1, dc2] = await createDataChannelPair(pc1, pc2); + await awaitMessage(dc2); + assert_equals(dc1.bufferedAmount, 0, + 'Expect sender bufferedAmount to be reduced after message is sent'); + }, `${mode} bufferedAmount should increase to byte length of buffer sent`); - dc1.send(helloBuffer.buffer); - assert_equals(dc1.bufferedAmount, helloBuffer.byteLength, - 'Expect bufferedAmount to increase to byte length of sent buffer'); + /* + 6.2. send() + 3. Execute the sub step that corresponds to the type of the methods argument: + Blob object + Let data be the raw data represented by the Blob object and increase + the bufferedAmount attribute by the size of data, in bytes. + */ + promise_test(async (t) => { + const [dc1, dc2] = await createDataChannelPair(t, options); - await awaitMessage(dc2); - assert_equals(dc1.bufferedAmount, 0, - 'Expect sender bufferedAmount to be reduced after message is sent'); -}, 'bufferedAmount should increase to byte length of buffer sent'); + dc1.send(helloBlob); + assert_equals(dc1.bufferedAmount, helloBlob.size, + 'Expect bufferedAmount to increase to size of sent blob'); -/* - 6.2. send() - 3. Execute the sub step that corresponds to the type of the methods argument: - Blob object - Let data be the raw data represented by the Blob object and increase - the bufferedAmount attribute by the size of data, in bytes. - */ -promise_test(async (t) => { - const pc1 = new RTCPeerConnection(); - const pc2 = new RTCPeerConnection(); - t.add_cleanup(() => pc1.close()); - t.add_cleanup(() => pc2.close()); + await awaitMessage(dc2); + assert_equals(dc1.bufferedAmount, 0, + 'Expect sender bufferedAmount to be reduced after message is sent'); + }, `${mode} bufferedAmount should increase to size of blob sent`); - const [dc1, dc2] = await createDataChannelPair(pc1, pc2); + // Test sending 3 messages: helloBuffer, unicodeString, helloBlob + promise_test(async (t) => { + const resolver = new Resolver(); + let messageCount = 0; - dc1.send(helloBlob); - assert_equals(dc1.bufferedAmount, helloBlob.size, - 'Expect bufferedAmount to increase to size of sent blob'); + const [dc1, dc2] = await createDataChannelPair(t, options); + dc2.onmessage = t.step_func(() => { + if (++messageCount === 3) { + assert_equals(dc1.bufferedAmount, 0, + 'Expect sender bufferedAmount to be reduced after message is sent'); + resolver.resolve(); + } + }); - await awaitMessage(dc2); - assert_equals(dc1.bufferedAmount, 0, - 'Expect sender bufferedAmount to be reduced after message is sent'); -}, 'bufferedAmount should increase to size of blob sent'); + dc1.send(helloBuffer); + assert_equals(dc1.bufferedAmount, helloString.length, + 'Expect bufferedAmount to be the total length of all messages queued to send'); -// Test sending 3 messages: helloBuffer, unicodeString, helloBlob -promise_test(async (t) => { - const resolver = new Resolver(); - const pc1 = new RTCPeerConnection(); - const pc2 = new RTCPeerConnection(); - t.add_cleanup(() => pc1.close()); - t.add_cleanup(() => pc2.close()); + dc1.send(unicodeString); + assert_equals(dc1.bufferedAmount, + helloString.length + unicodeBuffer.byteLength, + 'Expect bufferedAmount to be the total length of all messages queued to send'); - let messageCount = 0; + dc1.send(helloBlob); + assert_equals(dc1.bufferedAmount, + helloString.length*2 + unicodeBuffer.byteLength, + 'Expect bufferedAmount to be the total length of all messages queued to send'); - const [dc1, dc2] = await createDataChannelPair(pc1, pc2); - const onMessage = t.step_func(() => { - if (++messageCount === 3) { - assert_equals(dc1.bufferedAmount, 0, - 'Expect sender bufferedAmount to be reduced after message is sent'); - resolver.resolve(); - } - }); + await resolver; + }, `${mode} bufferedAmount should increase by byte length for each message sent`); - dc2.addEventListener('message', onMessage); + promise_test(async (t) => { + const [dc1] = await createDataChannelPair(t, options); - dc1.send(helloBuffer); - assert_equals(dc1.bufferedAmount, helloString.length, - 'Expect bufferedAmount to be the total length of all messages queued to send'); + dc1.send(helloBuffer.buffer); + assert_equals(dc1.bufferedAmount, helloBuffer.byteLength, + 'Expect bufferedAmount to increase to byte length of sent buffer'); - dc1.send(unicodeString); - assert_equals(dc1.bufferedAmount, - helloString.length + unicodeBuffer.byteLength, - 'Expect bufferedAmount to be the total length of all messages queued to send'); + dc1.close(); + assert_equals(dc1.bufferedAmount, helloBuffer.byteLength, + 'Expect bufferedAmount to not decrease immediately after closing the channel'); + }, `${mode} bufferedAmount should not decrease immediately after initiating closure`); - dc1.send(helloBlob); - assert_equals(dc1.bufferedAmount, - helloString.length*2 + unicodeBuffer.byteLength, - 'Expect bufferedAmount to be the total length of all messages queued to send'); + promise_test(async (t) => { + const pc1 = new RTCPeerConnection(); + t.add_cleanup(() => pc1.close()); + const [dc1] = await createDataChannelPair(t, options, pc1); - await resolver; -}, 'bufferedAmount should increase by byte length for each message sent'); + dc1.send(helloBuffer.buffer); + assert_equals(dc1.bufferedAmount, helloBuffer.byteLength, + 'Expect bufferedAmount to increase to byte length of sent buffer'); -promise_test(async (t) => { - const pc1 = new RTCPeerConnection(); - const pc2 = new RTCPeerConnection(); - t.add_cleanup(() => pc1.close()); - t.add_cleanup(() => pc2.close()); - - const [dc1] = await createDataChannelPair(pc1, pc2); - - dc1.send(helloBuffer.buffer); - assert_equals(dc1.bufferedAmount, helloBuffer.byteLength, - 'Expect bufferedAmount to increase to byte length of sent buffer'); - - dc1.close(); - assert_equals(dc1.bufferedAmount, helloBuffer.byteLength, - 'Expect bufferedAmount to not decrease immediately after closing the channel'); -}, 'bufferedAmount should not decrease immediately after initiating closure'); - -promise_test(async (t) => { - const pc1 = new RTCPeerConnection(); - const pc2 = new RTCPeerConnection(); - t.add_cleanup(() => pc1.close()); - t.add_cleanup(() => pc2.close()); - - const [dc1] = await createDataChannelPair(pc1, pc2); - - dc1.send(helloBuffer.buffer); - assert_equals(dc1.bufferedAmount, helloBuffer.byteLength, - 'Expect bufferedAmount to increase to byte length of sent buffer'); - - pc1.close(); - assert_equals(dc1.bufferedAmount, helloBuffer.byteLength, - 'Expect bufferedAmount to not decrease after closing the peer connection'); -}, 'bufferedAmount should not decrease after closing the peer connection'); + pc1.close(); + assert_equals(dc1.bufferedAmount, helloBuffer.byteLength, + 'Expect bufferedAmount to not decrease after closing the peer connection'); + }, `${mode} bufferedAmount should not decrease after closing the peer connection`); promise_test(async t => { - const [channel1, channel2] = await createDataChannelPair(); + const [channel1, channel2] = await createDataChannelPair(t, options); channel1.addEventListener('bufferedamountlow', t.step_func_done(() => { assert_true(channel1.bufferedAmount <= channel1.bufferedAmountLowThreshold); })); const eventWatcher = new EventWatcher(t, channel1, ['bufferedamountlow']); channel1.send(helloString); await eventWatcher.wait_for(['bufferedamountlow']); - }, 'Data channel bufferedamountlow event fires after send() is complete'); + }, `${mode} bufferedamountlow event fires after send() is complete`); promise_test(async t => { - const [channel1, channel2] = await createDataChannelPair(); + const [channel1, channel2] = await createDataChannelPair(t, options); channel1.send(helloString); assert_equals(channel1.bufferedAmount, helloString.length); await awaitMessage(channel2); assert_equals(channel1.bufferedAmount, 0); - }, 'Data channel bufferedamount is data.length on send(data)'); + }, `${mode} bufferedamount is data.length on send(data)`); promise_test(async t => { - const [channel1, channel2] = await createDataChannelPair(); + const [channel1, channel2] = await createDataChannelPair(t, options); channel1.send(helloString); assert_equals(channel1.bufferedAmount, helloString.length); assert_equals(channel1.bufferedAmount, helloString.length); - }, 'Data channel bufferedamount returns the same amount if no more data is' + - ' sent on the channel'); + }, `${mode} bufferedamount returns the same amount if no more data is`); promise_test(async t => { - const [channel1, channel2] = await createDataChannelPair(); + const [channel1, channel2] = await createDataChannelPair(t, options); let eventFireCount = 0; channel1.addEventListener('bufferedamountlow', t.step_func(() => { assert_true(channel1.bufferedAmount <= channel1.bufferedAmountLowThreshold); @@ -262,11 +230,11 @@ promise_test(async (t) => { channel1.send(helloString); assert_equals(channel1.bufferedAmount, 2 * helloString.length); await eventWatcher.wait_for(['bufferedamountlow']); - }, 'Data channel bufferedamountlow event fires only once after multiple' + - ' consecutive send() calls'); + }, `${mode} bufferedamountlow event fires only once after multiple` + + ` consecutive send() calls`); promise_test(async t => { - const [channel1, channel2] = await createDataChannelPair(); + const [channel1, channel2] = await createDataChannelPair(t, options); const eventWatcher = new EventWatcher(t, channel1, ['bufferedamountlow']); channel1.send(helloString); assert_equals(channel1.bufferedAmount, helloString.length); @@ -276,6 +244,6 @@ promise_test(async (t) => { assert_equals(channel1.bufferedAmount, helloString.length); await eventWatcher.wait_for(['bufferedamountlow']); assert_equals(await awaitMessage(channel2), helloString); - }, 'Data channel bufferedamountlow event fires after each sent message'); - + }, `${mode} bufferedamountlow event fires after each sent message`); +} diff --git a/tests/wpt/web-platform-tests/webrtc/RTCDataChannel-close.html b/tests/wpt/web-platform-tests/webrtc/RTCDataChannel-close.html index ea7795719c2..00b081b2e2f 100644 --- a/tests/wpt/web-platform-tests/webrtc/RTCDataChannel-close.html +++ b/tests/wpt/web-platform-tests/webrtc/RTCDataChannel-close.html @@ -8,94 +8,93 @@ diff --git a/tests/wpt/web-platform-tests/webrtc/RTCDataChannel-send-blob-order.html b/tests/wpt/web-platform-tests/webrtc/RTCDataChannel-send-blob-order.html index f5cdb45e04c..3fcf116bc8d 100644 --- a/tests/wpt/web-platform-tests/webrtc/RTCDataChannel-send-blob-order.html +++ b/tests/wpt/web-platform-tests/webrtc/RTCDataChannel-send-blob-order.html @@ -5,13 +5,17 @@ diff --git a/tests/wpt/web-platform-tests/webrtc/RTCDataChannel-send.html b/tests/wpt/web-platform-tests/webrtc/RTCDataChannel-send.html index 3a4c0f56d65..1952921fbf2 100644 --- a/tests/wpt/web-platform-tests/webrtc/RTCDataChannel-send.html +++ b/tests/wpt/web-platform-tests/webrtc/RTCDataChannel-send.html @@ -6,56 +6,59 @@ diff --git a/tests/wpt/web-platform-tests/webrtc/RTCIceTransport.html b/tests/wpt/web-platform-tests/webrtc/RTCIceTransport.html index 94dc1c461fb..fe12c384e5e 100644 --- a/tests/wpt/web-platform-tests/webrtc/RTCIceTransport.html +++ b/tests/wpt/web-platform-tests/webrtc/RTCIceTransport.html @@ -123,7 +123,7 @@ const pc2 = new RTCPeerConnection(); t.add_cleanup(() => pc2.close()); - return createDataChannelPair(pc1, pc2) + return createDataChannelPair(t, {}, pc1, pc2) .then(([channel1, channel2]) => { // Send a ping message and wait for it just to make sure // that the connection is fully working before testing diff --git a/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-createDataChannel.html b/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-createDataChannel.html index dd34561fbc6..3d2169dffac 100644 --- a/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-createDataChannel.html +++ b/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-createDataChannel.html @@ -666,66 +666,66 @@ promise_test(async t => { }, 'Reusing a data channel id that is in use (after setRemoteDescription, negotiated via DCEP) ' + 'should throw OperationError'); -// Based on https://bugzilla.mozilla.org/show_bug.cgi?id=1441723 -promise_test(async t => { - const pc1 = new RTCPeerConnection(); - const pc2 = new RTCPeerConnection(); - t.add_cleanup(() => pc1.close()); - t.add_cleanup(() => pc2.close()); - await createDataChannelPair(pc1, pc2); +for (const options of [{}, {negotiated: true, id: 0}]) { + const mode = `${options.negotiated? "negotiated " : ""}datachannel`; - const dc = pc1.createDataChannel(''); - assert_equals(dc.readyState, 'connecting', 'Channel should be in the connecting state'); -}, 'New data channel should be in the connecting state after creation (after connection ' + - 'establishment)'); + // Based on https://bugzilla.mozilla.org/show_bug.cgi?id=1441723 + promise_test(async t => { + const pc1 = new RTCPeerConnection(); + t.add_cleanup(() => pc1.close()); -promise_test(async t => { - const pc1 = new RTCPeerConnection(); - const pc2 = new RTCPeerConnection(); - t.add_cleanup(() => pc1.close()); - t.add_cleanup(() => pc2.close()); - const stream = await getNoiseStream({audio: true, video: true}); - t.add_cleanup(() => stopTracks(stream)); - const audio = stream.getAudioTracks()[0]; - const video = stream.getVideoTracks()[0]; - pc1.addTrack(audio, stream); - pc1.addTrack(video, stream); - await createDataChannelPair(pc1, pc2); -}, 'addTrack, then createDataChannel, should negotiate properly'); + await createDataChannelPair(t, options, pc1); -promise_test(async t => { - const pc1 = new RTCPeerConnection({bundlePolicy: "max-bundle"}); - const pc2 = new RTCPeerConnection(); - t.add_cleanup(() => pc1.close()); - t.add_cleanup(() => pc2.close()); - const stream = await getNoiseStream({audio: true, video: true}); - t.add_cleanup(() => stopTracks(stream)); - const audio = stream.getAudioTracks()[0]; - const video = stream.getVideoTracks()[0]; - pc1.addTrack(audio, stream); - pc1.addTrack(video, stream); - await createDataChannelPair(pc1, pc2); -}, 'addTrack, then createDataChannel, should negotiate properly when max-bundle is used'); + const dc = pc1.createDataChannel(''); + assert_equals(dc.readyState, 'connecting', 'Channel should be in the connecting state'); + }, `New ${mode} should be in the connecting state after creation ` + + `(after connection establishment)`); -promise_test(async t => { - const pc1 = new RTCPeerConnection({bundlePolicy: "max-bundle"}); - const pc2 = new RTCPeerConnection(); - t.add_cleanup(() => pc1.close()); - t.add_cleanup(() => pc2.close()); - const stream = await getNoiseStream({audio: true, video: true}); - t.add_cleanup(() => stopTracks(stream)); - const audio = stream.getAudioTracks()[0]; - const video = stream.getVideoTracks()[0]; - pc1.addTrack(audio, stream); - pc1.addTrack(video, stream); - const [dc1, dc2] = await createDataChannelPair(pc1, pc2); + promise_test(async t => { + const pc1 = new RTCPeerConnection(); + t.add_cleanup(() => pc1.close()); + const stream = await getNoiseStream({audio: true, video: true}); + t.add_cleanup(() => stopTracks(stream)); + const audio = stream.getAudioTracks()[0]; + const video = stream.getVideoTracks()[0]; + pc1.addTrack(audio, stream); + pc1.addTrack(video, stream); + await createDataChannelPair(t, options, pc1); + }, `addTrack, then creating ${mode}, should negotiate properly`); - pc2.getTransceivers()[0].stop(); - const dc1Closed = new Promise(r => dc1.onclose = r); - await exchangeOfferAnswer(pc1, pc2); - await dc1Closed; -}, 'Stopping the bundle-tag when there is a DataChannel in the bundle should kill the DataChannel'); + promise_test(async t => { + const pc1 = new RTCPeerConnection({bundlePolicy: "max-bundle"}); + t.add_cleanup(() => pc1.close()); + const stream = await getNoiseStream({audio: true, video: true}); + t.add_cleanup(() => stopTracks(stream)); + const audio = stream.getAudioTracks()[0]; + const video = stream.getVideoTracks()[0]; + pc1.addTrack(audio, stream); + pc1.addTrack(video, stream); + await createDataChannelPair(t, options, pc1); + }, `addTrack, then creating ${mode}, should negotiate properly when max-bundle is used`); + + promise_test(async t => { + const pc1 = new RTCPeerConnection({bundlePolicy: "max-bundle"}); + const pc2 = new RTCPeerConnection(); + t.add_cleanup(() => pc1.close()); + t.add_cleanup(() => pc2.close()); + const stream = await getNoiseStream({audio: true, video: true}); + t.add_cleanup(() => stopTracks(stream)); + const audio = stream.getAudioTracks()[0]; + const video = stream.getVideoTracks()[0]; + pc1.addTrack(audio, stream); + pc1.addTrack(video, stream); + const [dc1, dc2] = await createDataChannelPair(t, options, pc1, pc2); + + pc2.getTransceivers()[0].stop(); + const dc1Closed = new Promise(r => dc1.onclose = r); + await exchangeOfferAnswer(pc1, pc2); + await dc1Closed; + }, `Stopping the bundle-tag when there is a ${mode} in the bundle ` + + `should kill the DataChannel`); +} /* Untestable diff --git a/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-helper.js b/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-helper.js index b7ed92a9cd2..531a8a7f4ff 100644 --- a/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-helper.js +++ b/tests/wpt/web-platform-tests/webrtc/RTCPeerConnection-helper.js @@ -303,21 +303,36 @@ function listenForSSRCs(t, receiver) { }); } -// Helper function to create a pair of connected data channel. +// Helper function to create a pair of connected data channels. // On success the promise resolves to an array with two data channels. // It does the heavy lifting of performing signaling handshake, // ICE candidate exchange, and waiting for data channel at two -// end points to open. -async function createDataChannelPair( - pc1 = new RTCPeerConnection(), - pc2 = new RTCPeerConnection()) { - const pair = [pc1, pc2].map(pc => - pc.createDataChannel('', {negotiated: true, id: 0})); - const bothOpen = Promise.all(pair.map(dc => new Promise((r, e) => { - dc.onopen = r; - dc.onerror = ({error}) => e(error); - }))); +// end points to open. Can do both negotiated and non-negotiated setup. +async function createDataChannelPair(t, options, + pc1 = createPeerConnectionWithCleanup(t), + pc2 = createPeerConnectionWithCleanup(t)) { + let pair = [], bothOpen; try { + if (options.negotiated) { + pair = [pc1, pc2].map(pc => pc.createDataChannel('', options)); + bothOpen = Promise.all(pair.map(dc => new Promise((r, e) => { + dc.onopen = r; + dc.onerror = ({error}) => e(error); + }))); + } else { + pair = [pc1.createDataChannel('', options)]; + bothOpen = Promise.all([ + new Promise((r, e) => { + pair[0].onopen = r; + pair[0].onerror = ({error}) => e(error); + }), + new Promise((r, e) => pc2.ondatachannel = ({channel}) => { + pair[1] = channel; + channel.onopen = r; + channel.onerror = ({error}) => e(error); + }) + ]); + } exchangeIceCandidates(pc1, pc2); await exchangeOfferAnswer(pc1, pc2); await bothOpen; diff --git a/tests/wpt/web-platform-tests/webtransport/quic/constructor.any.js b/tests/wpt/web-platform-tests/webtransport/quic/constructor.any.js new file mode 100644 index 00000000000..393cefd5d30 --- /dev/null +++ b/tests/wpt/web-platform-tests/webtransport/quic/constructor.any.js @@ -0,0 +1,31 @@ +// META: global=window,worker +// META: script=/common/get-host-info.sub.js + +const HOST = get_host_info().ORIGINAL_HOST; + +const BAD_URLS = [ + null, + '', + 'no-scheme', + 'https://example.com/' /* scheme is wrong */, + 'quic-transport:///' /* no host specified */, + 'quic-transport://example.com/#failing' /* has fragment */, + `quic-transport://${HOST}:999999/` /* invalid port */, +]; + +for (const url of BAD_URLS) { + test(() => { + assert_throws_dom('SyntaxError', () => new QuicTransport(url), + 'constructor should throw'); + }, `QuicTransport constructor should reject URL '${url}'`); +} + +// TODO(ricea): Test CSP. + +promise_test(t => { + const qt = new QuicTransport(`quic-transport://${HOST}:0/`); + return Promise.all([ + promise_rejects_js(t, TypeError, qt.ready, 'ready promise rejects'), + promise_rejects_js(t, TypeError, qt.closed, 'closed promise rejects'), + ]); +}, 'connection to port 0 should fail');