diff --git a/.github/workflows/acceptance_tests.yaml b/.github/workflows/acceptance_tests.yaml new file mode 100644 index 00000000000..414f0b5e062 --- /dev/null +++ b/.github/workflows/acceptance_tests.yaml @@ -0,0 +1,23 @@ +name: Acceptance Tests +on: + pull_request: + branches: + - master + push: + branches: + - master + +jobs: + acceptance-tests: + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v3 + - name: run tests + run: acceptance-tests/run + - name: Upload test results + if: ${{ failure() }} + uses: actions/upload-artifact@v2 + with: + name: tests-result + path: ats/result diff --git a/.github/workflows/browser-e2e.yaml b/.github/workflows/browser-e2e.yaml deleted file mode 100644 index b45f63710c1..00000000000 --- a/.github/workflows/browser-e2e.yaml +++ /dev/null @@ -1,20 +0,0 @@ -name: Browser E2E -on: - pull_request: - branches: - - master - push: - branches: - - master - -jobs: - e2e-test: - name: Test - runs-on: ubuntu-latest - steps: - - name: checkout - uses: actions/checkout@v3 - - name: test - run: | - docker build -t pion-webrtc-e2e -f e2e/Dockerfile . - docker run -i --rm pion-webrtc-e2e diff --git a/.github/workflows/examples-tests.yaml b/.github/workflows/examples-tests.yaml deleted file mode 100644 index 1791be42e49..00000000000 --- a/.github/workflows/examples-tests.yaml +++ /dev/null @@ -1,19 +0,0 @@ -name: Examples Tests -on: - pull_request: - branches: - - master - push: - branches: - - master - -jobs: - pion-to-pion-test: - name: Test - runs-on: ubuntu-latest - steps: - - name: checkout - uses: actions/checkout@v3 - - name: test - run: cd examples/pion-to-pion && ./test.sh - diff --git a/acceptance-tests/.gitignore b/acceptance-tests/.gitignore new file mode 100644 index 00000000000..c4e558971d5 --- /dev/null +++ b/acceptance-tests/.gitignore @@ -0,0 +1,2 @@ +rseult +assets diff --git a/acceptance-tests/README.md b/acceptance-tests/README.md new file mode 100644 index 00000000000..7cc570b6530 --- /dev/null +++ b/acceptance-tests/README.md @@ -0,0 +1,73 @@ +# Acceptance Test Procedure + +TL:DR; From the project's root `./acceptance-tests/run` + +This directory contains Acceptance Test Procedure AKA black box tests. +The tests are running over a lab managed by docker-compose and using playwright +for browser automation. + +The `acceptance-tests` directory includes a special directory `infra` with the infrastructure +required by the tests. +For example, there's a `./infra/pion` directory with a Dockerfile and an SSH +config file. + +Unlike production containers, lab containers' entry point +often includes setup code usually found in the Dockerfile. +This is done for flexibility and speed as we want the lab to use the latest source + +The script support some old style options, use `./acceptance-tests/run -h` to see the +all the options. It also accepts one of more argument with a directory name. + +## The setup + +We use [playwright](https://playwright.dev) as the test runner. +In addition to browser automation the runner uses SSH to control the services. +Thanks to compose, a name of a service is also its address so + +The runner supports one environment variable - `PWOPTS` - one can use to pass +options to playwright. The default is `-x` stopping the test on the first +failure. It's rigged this way becuase ATPs are usually complex scenarios. +Unlike unit tests, where each test function is independent, here each functions +is a step in one test procedure. Once a step failed, `-x` makes playwright ignore +the rest of the file. + +To get help on playwright options run: + +```bash +docker compose -f acceptance-tests/data-channels/lab.yaml --project-directory . run --entrypoint "npx playwright test --help" runner +``` + +The above command uses the lab from the data-channels tests to bring up a runner +and override its entrypoint. Instead of running the specs, get help on playwright. +We use `--project-directory .` in all the tests to ensure the relative paths are +relative to the project's root. + +## Adding a test + +To create the `fubar` test, create a new directory in `./acceptance-tests/fubar` and start working +one your `lab.yaml`. If your tests include a browser client your runner is +best using the image from `infra/playwright`: + +```yaml +version: "3.9" +services: + runner: + build: + context: . + dockerfile: ./acceptance-tests/infra/playwright/Dockerfile + volumes: + - ./acceptance-tests/fubar:/specs + - ./acceptance-tests/result:/result + environment: + PWOPTS: ${PWOPTS--x} +``` + +Not that we are mapping `/specs` to `acceptance-tests/fubar` as the first is where the image looks +for specs. Once you've added your specs file to `./acceptance-tests/fubar` it will run whener you +`./acceptance-tests/run`. In fact, all a sub-directory of acceptance-tests needs is a `lab.yaml` file and the +run script will try to bring it up. + +If you want to run just fubar you can use `./acceptance-tests/run acceptance-tests/fubar`. +To run a clean build of fubar, ignoring all cache, use `-z`. + + diff --git a/acceptance-tests/data-channels/example.spec.ts b/acceptance-tests/data-channels/example.spec.ts new file mode 100644 index 00000000000..5f21a18ac3a --- /dev/null +++ b/acceptance-tests/data-channels/example.spec.ts @@ -0,0 +1,125 @@ +import { Buffer } from 'node:buffer'; +import { test, expect, Page, BrowserContext } from '@playwright/test' +import { Client } from 'ssh2' + + +test.describe("pion's data channels example", () => { + + const sleep = (ms) => { return new Promise(r => setTimeout(r, ms)) } + + let page: Page + let context: BrowserContext + let SSHconn: Client + let stream + + test.beforeAll(async ({ browser }) => { + context = await browser.newContext() + page = await context.newPage() + page.on('console', (msg) => console.log('console log:', msg.text())) + page.on('pageerror', (err: Error) => console.log('PAGEERROR', err.message)) + // Load the javascript file + page.on('load', () => page.evaluate(() => { + var newScript = document.createElement('script') + newScript.src = 'demo.js' + document.head.appendChild(newScript) + }) + ) + const response = await page.goto("http://client/demo.html") + await expect(response.ok()).toBeTruthy() + SSHconn = null + }) + + test('setup SSH', async () => { + while (SSHconn == null) { + try { + SSHconn = await new Promise((resolve, reject) => { + const SSHconn = new Client() + SSHconn.on('error', e => reject(e)) + SSHconn.on('ready', () => resolve(SSHconn)) + SSHconn.connect({ + host: 'pion', + port: 22, + username: 'pion', + password: 'pion' + }) + }) + } catch(e) { + console.log("SSH connection failed, retrying") + await sleep(3000) + } + } + // log key SSH events + SSHconn.on('error', e => console.log("ssh error", e)) + SSHconn.on('close', e => { + console.log("ssh closed", e) + }) + SSHconn.on('end', e => console.log("ssh ended", e)) + SSHconn.on('keyboard-interactive', e => console.log("ssh interaction", e)) + }) + test('open the command stream', async () => { + let offer + while (!offer) { + await sleep(200) + offer = await page.evaluate(() => + document.getElementById('localSessionDescription').value + ) + } + try { + stream = await new Promise((resolve, reject) => { + const path = "/go/src/github.com/pion/webrtc/acceptance-tests/data-channels/start_server.bash" + SSHconn.exec(`bash ${path} ${offer}`, + { pty: true }, async (err, s) => { + if (err) + reject(err) + else + resolve(s) + }) + }) + } catch(e) { expect(e).toBeNull() } + stream.on('close', (code, signal) => { + console.log(`SSH closed with ${signal}`) + SSHconn.end() + }) + }) + test('transmit and receive data', async()=> { + let eof = false + let lineCounter = 0 + stream.on('data', lines => + new Buffer.from(lines).toString().split("\r\n") + .forEach(async (line: string) => { + if (!line) + return + lineCounter++ + if (lineCounter == 1) { + // copy the answer to the page + await page.evaluate(async (answer) => + document.getElementById("remoteSessionDescription") + .value = answer, + line) + page.locator("data-test-id=start-session").click() + // set the message to EOF + await page.evaluate(async () => + document.getElementById("message").value = "EOF") + // wait for the send channel to open + let connected = false + while (!connected) { + await sleep(200) + connected = await page.evaluate(() => sendChannel.readyState == "open") + } + // send the message + await page.locator("data-test-id=send-message").click() + return + } + // exit the test when EOF was received from the server + if (line.includes("EOF")) + eof = true + }) + ).stderr.on('data', (data) => { + console.log("ERROR: " + data) + }) + // wait for the EOF message + while (!eof) { + await sleep(200) + } + }) +}) diff --git a/acceptance-tests/data-channels/lab.yaml b/acceptance-tests/data-channels/lab.yaml new file mode 100644 index 00000000000..c54d8ffa482 --- /dev/null +++ b/acceptance-tests/data-channels/lab.yaml @@ -0,0 +1,30 @@ +version: "3.9" +services: + runner: + build: + context: . + dockerfile: ./acceptance-tests/infra/playwright/Dockerfile + volumes: + - ./acceptance-tests/data-channels:/specs + - ./acceptance-tests/result:/result + depends_on: + - client + - pion + environment: + PWOPTS: ${PWOPTS--x} + client: + image: halverneus/static-file-server:latest + environment: + PORT: 80 + expose: + - "80" + volumes: + - ./examples/data-channels/jsfiddle:/web + pion: + build: + context: . + dockerfile: ./acceptance-tests/infra/pion/Dockerfile + expose: + - "22" + volumes: + - .:/go/src/github.com/pion/webrtc diff --git a/acceptance-tests/data-channels/start_server.bash b/acceptance-tests/data-channels/start_server.bash new file mode 100644 index 00000000000..2228d451f80 --- /dev/null +++ b/acceptance-tests/data-channels/start_server.bash @@ -0,0 +1,14 @@ +#!/bin/bash +GO=/usr/local/go/bin/go +cd "/go/src/github.com/pion/webrtc/examples/data-channels" +TMP=`mktemp` +$GO build -buildvcs=false -o $HOME/datachannels . > $TMP 2>&1 + +if [ $? -eq 0 ]; then + echo $1 | $HOME/datachannels +else + # on error send the last 5 lines of output as a single line + # so it's displayed in the browser + tail -5 $TMP | tr '\n' ':' +fi +rm $TMP diff --git a/e2e/Dockerfile b/acceptance-tests/e2e/Dockerfile similarity index 65% rename from e2e/Dockerfile rename to acceptance-tests/e2e/Dockerfile index c871222afb7..e1a80f1c797 100644 --- a/e2e/Dockerfile +++ b/acceptance-tests/e2e/Dockerfile @@ -6,7 +6,6 @@ RUN apk add --no-cache \ ENV CGO_ENABLED=0 -COPY . /go/src/github.com/pion/webrtc -WORKDIR /go/src/github.com/pion/webrtc/e2e +WORKDIR /go/src/github.com/pion/webrtc/acceptance-tests/e2e CMD ["go", "test", "-tags=e2e", "-v", "."] diff --git a/e2e/e2e_test.go b/acceptance-tests/e2e/e2e_test.go similarity index 100% rename from e2e/e2e_test.go rename to acceptance-tests/e2e/e2e_test.go diff --git a/acceptance-tests/e2e/lab.yaml b/acceptance-tests/e2e/lab.yaml new file mode 100644 index 00000000000..4d403bf5160 --- /dev/null +++ b/acceptance-tests/e2e/lab.yaml @@ -0,0 +1,8 @@ +version: "3.9" +services: + runner: + build: + context: . + dockerfile: ./acceptance-tests/e2e/Dockerfile + volumes: + - .:/go/src/github.com/pion/webrtc diff --git a/e2e/test.html b/acceptance-tests/e2e/test.html similarity index 100% rename from e2e/test.html rename to acceptance-tests/e2e/test.html diff --git a/acceptance-tests/infra/pion/Dockerfile b/acceptance-tests/infra/pion/Dockerfile new file mode 100644 index 00000000000..52d51f72953 --- /dev/null +++ b/acceptance-tests/infra/pion/Dockerfile @@ -0,0 +1,9 @@ +FROM golang:bullseye +RUN apt-get update +RUN apt-get install -y git bash openssh-server +COPY ./acceptance-tests/infra/pion/ssh_config /etc/ssh/ +# pion user with pion password to be used by clients' ssh connections +RUN useradd -s /bin/bash -d /home/pion -M -p '$y$j9T$6LsNr6MtK4Nt6NeECphjP1$Try0q9dVUdZGihzzxJZ0soO09wQhseYzyB/E2Jf4tO8' pion +RUN mkdir /home/pion +RUN chown pion /home/pion +CMD /etc/init.d/ssh start && tail -f /dev/null diff --git a/acceptance-tests/infra/pion/ssh_config b/acceptance-tests/infra/pion/ssh_config new file mode 100644 index 00000000000..9484ed1839c --- /dev/null +++ b/acceptance-tests/infra/pion/ssh_config @@ -0,0 +1,9 @@ +Include /etc/ssh/ssh_config.d/*.conf +Host * +PasswordAuthentication yes +SendEnv LANG LC_* +HashKnownHosts yes +GSSAPIAuthentication yes +PermitEmptyPasswords yes +PermitRootLogin yes + diff --git a/acceptance-tests/infra/playwright/Dockerfile b/acceptance-tests/infra/playwright/Dockerfile new file mode 100644 index 00000000000..96fdeb1f79a --- /dev/null +++ b/acceptance-tests/infra/playwright/Dockerfile @@ -0,0 +1,9 @@ +FROM mcr.microsoft.com/playwright:v1.26.0-focal +ENV NODE_PATH="/usr/lib/node_modules" +RUN mkdir /runner +WORKDIR /runner +COPY ./acceptance-tests/infra/playwright/* . +RUN yarn install --frozen-lockfile +# /specs is set by lab.yaml, here copy the specs on run +# to make sure we're running the latest version +CMD cp /specs/*.spec.ts . && npx playwright test ${PWOPTS} diff --git a/acceptance-tests/infra/playwright/package.json b/acceptance-tests/infra/playwright/package.json new file mode 100644 index 00000000000..9a6eb73f763 --- /dev/null +++ b/acceptance-tests/infra/playwright/package.json @@ -0,0 +1,21 @@ +{ + "name": "pion-playwright", + "version": "0.1.0", + "private": true, + "description": "A playwright client for pion testing", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "@playwright/test": "^1.22.2", + "playwright-chromium": "^1.22.2", + "playwright-firefox": "^1.22.2", + "playwright-webkit": "^1.22.2", + "redis": "<5", + "ssh2": "~1.11.0", + "wait-port": "^0.2.9", + "@types/node": "^18.7.18" + } +} diff --git a/acceptance-tests/infra/playwright/playwright.config.ts b/acceptance-tests/infra/playwright/playwright.config.ts new file mode 100644 index 00000000000..4f502dd9eda --- /dev/null +++ b/acceptance-tests/infra/playwright/playwright.config.ts @@ -0,0 +1,36 @@ +// playwright.config.ts +import { PlaywrightTestConfig, devices } from '@playwright/test'; + +const config: PlaywrightTestConfig = { + headless: true, + forbidOnly: !!process.env.CI, + retries: 2, + outputDir: '/result', + use: { + trace: 'retain-on-failure', + }, + projects: [ + { + name: "chromium", + permissions:["camera", "microphone"], + + use:{ + browserName:"chromium", + launchOptions:{ + args: ['--use-fake-ui-for-media-stream', '--use-fake-device-for-media-stream'] + } + }, + }, + { + name: "firefox", + use: { + browserName:"firefox", + launchOptions: { + args:[ "--quiet", "--use-test-media-devices" ], + firefoxUserPrefs: { "media.navigator.streams.fake": true, "media.navigator.permission.disabled": true } + } + } + }, + ], +}; +export default config; diff --git a/acceptance-tests/infra/playwright/yarn.lock b/acceptance-tests/infra/playwright/yarn.lock new file mode 100644 index 00000000000..9653139008f --- /dev/null +++ b/acceptance-tests/infra/playwright/yarn.lock @@ -0,0 +1,227 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@playwright/test@^1.22.2": + version "1.26.0" + resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.26.0.tgz#d0c4a7ffaa7df5b4a63e0d8dea133fdb1d6c5aef" + integrity sha512-D24pu1k/gQw3Lhbpc38G5bXlBjGDrH5A52MsrH12wz6ohGDeQ+aZg/JFSEsT/B3G8zlJe/EU4EkJK74hpqsjEg== + dependencies: + "@types/node" "*" + playwright-core "1.26.0" + +"@redis/bloom@1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@redis/bloom/-/bloom-1.0.2.tgz#42b82ec399a92db05e29fffcdfd9235a5fc15cdf" + integrity sha512-EBw7Ag1hPgFzdznK2PBblc1kdlj5B5Cw3XwI9/oG7tSn85/HKy3X9xHy/8tm/eNXJYHLXHJL/pkwBpFMVVefkw== + +"@redis/client@1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@redis/client/-/client-1.3.0.tgz#c62ccd707f16370a2dc2f9e158a28b7da049fa77" + integrity sha512-XCFV60nloXAefDsPnYMjHGtvbtHR8fV5Om8cQ0JYqTNbWcQo/4AryzJ2luRj4blveWazRK/j40gES8M7Cp6cfQ== + dependencies: + cluster-key-slot "1.1.0" + generic-pool "3.8.2" + yallist "4.0.0" + +"@redis/graph@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@redis/graph/-/graph-1.0.1.tgz#eabc58ba99cd70d0c907169c02b55497e4ec8a99" + integrity sha512-oDE4myMCJOCVKYMygEMWuriBgqlS5FqdWerikMoJxzmmTUErnTRRgmIDa2VcgytACZMFqpAOWDzops4DOlnkfQ== + +"@redis/json@1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@redis/json/-/json-1.0.4.tgz#f372b5f93324e6ffb7f16aadcbcb4e5c3d39bda1" + integrity sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw== + +"@redis/search@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@redis/search/-/search-1.1.0.tgz#7abb18d431f27ceafe6bcb4dd83a3fa67e9ab4df" + integrity sha512-NyFZEVnxIJEybpy+YskjgOJRNsfTYqaPbK/Buv6W2kmFNaRk85JiqjJZA5QkRmWvGbyQYwoO5QfDi2wHskKrQQ== + +"@redis/time-series@1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@redis/time-series/-/time-series-1.0.3.tgz#4cfca8e564228c0bddcdf4418cba60c20b224ac4" + integrity sha512-OFp0q4SGrTH0Mruf6oFsHGea58u8vS/iI5+NpYdicaM+7BgqBZH8FFvNZ8rYYLrUO/QRqMq72NpXmxLVNcdmjA== + +"@types/node@*", "@types/node@^18.7.18": + version "18.7.23" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.23.tgz#75c580983846181ebe5f4abc40fe9dfb2d65665f" + integrity sha512-DWNcCHolDq0ZKGizjx2DZjR/PqsYwAcYUJmfMWqtVU2MBMG5Mo+xFZrhGId5r/O5HOuMPyQEcM6KUBp5lBZZBg== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +asn1@^0.2.4: + version "0.2.6" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" + integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== + dependencies: + safer-buffer "~2.1.0" + +bcrypt-pbkdf@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w== + dependencies: + tweetnacl "^0.14.3" + +buildcheck@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/buildcheck/-/buildcheck-0.0.3.tgz#70451897a95d80f7807e68fc412eb2e7e35ff4d5" + integrity sha512-pziaA+p/wdVImfcbsZLNF32EiWyujlQLwolMqUQE8xpKNOH7KmZQaY8sXN7DGOEzPAElo9QTaeNRfGnf3iOJbA== + +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +cluster-key-slot@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d" + integrity sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw== + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +commander@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/commander/-/commander-3.0.2.tgz#6837c3fb677ad9933d1cfba42dd14d5117d6b39e" + integrity sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow== + +cpu-features@~0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/cpu-features/-/cpu-features-0.0.4.tgz#0023475bb4f4c525869c162e4108099e35bf19d8" + integrity sha512-fKiZ/zp1mUwQbnzb9IghXtHtDoTMtNeb8oYGx6kX2SYfhnG0HNdBEBIzB9b5KlXu5DQPhfy3mInbBxFcgwAr3A== + dependencies: + buildcheck "0.0.3" + nan "^2.15.0" + +debug@^4.1.1: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +generic-pool@3.8.2: + version "3.8.2" + resolved "https://registry.yarnpkg.com/generic-pool/-/generic-pool-3.8.2.tgz#aab4f280adb522fdfbdc5e5b64d718d3683f04e9" + integrity sha512-nGToKy6p3PAbYQ7p1UlWl6vSPwfwU6TMSWK7TTu+WUY4ZjyZQGniGGt2oNVvyNSpyZYSB43zMXVLcBm08MTMkg== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +nan@^2.15.0, nan@^2.16.0: + version "2.16.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.16.0.tgz#664f43e45460fb98faf00edca0bb0d7b8dce7916" + integrity sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA== + +playwright-chromium@^1.22.2: + version "1.26.0" + resolved "https://registry.yarnpkg.com/playwright-chromium/-/playwright-chromium-1.26.0.tgz#fa4e75a2034a016b9e2e825fc6577f3efb0d2792" + integrity sha512-4hDiVmMKmtuHW5ne11S1HCQTdL+wytprQMhWYecEjMSIKBR1DJ3JLrcUDgqA0L5Jzi/CBKYQQk6TOVlTjXybXQ== + dependencies: + playwright-core "1.26.0" + +playwright-core@1.26.0: + version "1.26.0" + resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.26.0.tgz#850228f0638d410a5cdd69800d552f60e4d295cd" + integrity sha512-p8huU8eU4gD3VkJd3DA1nA7R3XA6rFvFL+1RYS96cSljCF2yJE9CWEHTPF4LqX8KN9MoWCrAfVKP5381X3CZqg== + +playwright-firefox@^1.22.2: + version "1.26.0" + resolved "https://registry.yarnpkg.com/playwright-firefox/-/playwright-firefox-1.26.0.tgz#4375e8c4eff71c169237260840cf13042527eb89" + integrity sha512-9cKbCBQo4VUeKUdBHkh5Cwx95DPbYr3JYlAJWJlAcItBqlTyxUSfXrptBA7zwZCMQ11cjBAVuumVRJhqOMplPQ== + dependencies: + playwright-core "1.26.0" + +playwright-webkit@^1.22.2: + version "1.26.0" + resolved "https://registry.yarnpkg.com/playwright-webkit/-/playwright-webkit-1.26.0.tgz#139f692d600c62cc34a5b59a6ec2fba2a18dd602" + integrity sha512-U9G4/pb4pRND3QF+Iv0JQGodIAbNLe02WSaW9DtQp91w4JkaZrP+iWfGGHCB409+rwiIfdCzVaWDp1ixfG1Mlw== + dependencies: + playwright-core "1.26.0" + +redis@<5: + version "4.3.1" + resolved "https://registry.yarnpkg.com/redis/-/redis-4.3.1.tgz#290532a0c22221e05e991162ac4dca1e1b2ff6da" + integrity sha512-cM7yFU5CA6zyCF7N/+SSTcSJQSRMEKN0k0Whhu6J7n9mmXRoXugfWDBo5iOzGwABmsWKSwGPTU5J4Bxbl+0mrA== + dependencies: + "@redis/bloom" "1.0.2" + "@redis/client" "1.3.0" + "@redis/graph" "1.0.1" + "@redis/json" "1.0.4" + "@redis/search" "1.1.0" + "@redis/time-series" "1.0.3" + +safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +ssh2@~1.11.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/ssh2/-/ssh2-1.11.0.tgz#ce60186216971e12f6deb553dcf82322498fe2e4" + integrity sha512-nfg0wZWGSsfUe/IBJkXVll3PEZ//YH2guww+mP88gTpuSU4FtZN7zu9JoeTGOyCNx2dTDtT9fOpWwlzyj4uOOw== + dependencies: + asn1 "^0.2.4" + bcrypt-pbkdf "^1.0.2" + optionalDependencies: + cpu-features "~0.0.4" + nan "^2.16.0" + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +tweetnacl@^0.14.3: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA== + +wait-port@^0.2.9: + version "0.2.14" + resolved "https://registry.yarnpkg.com/wait-port/-/wait-port-0.2.14.tgz#6df40629be2c95aa4073ceb895abef7d872b28c6" + integrity sha512-kIzjWcr6ykl7WFbZd0TMae8xovwqcqbx6FM9l+7agOgUByhzdjfzZBPK2CPufldTOMxbUivss//Sh9MFawmPRQ== + dependencies: + chalk "^2.4.2" + commander "^3.0.2" + debug "^4.1.1" + +yallist@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== diff --git a/acceptance-tests/pion-to-pion/lab.yaml b/acceptance-tests/pion-to-pion/lab.yaml new file mode 100644 index 00000000000..90221e1f8df --- /dev/null +++ b/acceptance-tests/pion-to-pion/lab.yaml @@ -0,0 +1,17 @@ +version: '3' +services: + answer: + image: golang:1.19 + volumes: + - .:/go/src/github.com/pion/webrtc + working_dir: /go/src/github.com/pion/webrtc/examples/pion-to-pion/answer + command: go run . -offer-address runner:50000 + + runner: + depends_on: + - answer + image: golang:1.19 + volumes: + - .:/go/src/github.com/pion/webrtc + working_dir: /go/src/github.com/pion/webrtc/examples/pion-to-pion/offer + command: go run . -answer-address answer:60000 -count 3 -wait 1 diff --git a/acceptance-tests/run b/acceptance-tests/run new file mode 100755 index 00000000000..e3eac679768 --- /dev/null +++ b/acceptance-tests/run @@ -0,0 +1,79 @@ +#!/usr/bin/env bash +BUILD=1 +build_n_run() { + + if [ $BUILD -eq 1 ] + then + docker compose -f $1 --project-directory . build $BUILD_OPTIONS + if [ $? -ne 0 ] + then + exit "docker compose build failed" + fi + fi + docker compose -f $1 --project-directory . up --exit-code-from runner +} +usage() { + cat <>> Setting a lab based on $dir" + build_n_run $compose + if [ $? -ne 0 ] + then + echo ">>> $dir tests FAILED" + exit 4 + fi + done +else + for arg in $@ + do + echo ">>> Setting a lab based on $arg" + build_n_run $arg/lab.yaml + if [ $? -ne 0 ] + then + echo ">>> $arg FAILED" + exit 4 + fi + echo ">>> $arg tests PASSED" + done +fi diff --git a/examples/data-channels/jsfiddle/demo.html b/examples/data-channels/jsfiddle/demo.html index b50aa880c4e..d1aab37c16e 100644 --- a/examples/data-channels/jsfiddle/demo.html +++ b/examples/data-channels/jsfiddle/demo.html @@ -8,14 +8,14 @@ Golang base64 Session Description

-
+

Message

-
+

Logs
-
\ No newline at end of file +
diff --git a/examples/pion-to-pion/README.md b/examples/pion-to-pion/README.md index 7bf909bb760..41dd9f236d3 100644 --- a/examples/pion-to-pion/README.md +++ b/examples/pion-to-pion/README.md @@ -19,9 +19,7 @@ offer You should see them connect and start to exchange messages. -## You can use Docker-compose to start this example: +## Running as a test ```sh -docker-compose up -d +./acceptance-tests/run acceptance-tests/pion-to-pion ``` - -Now, you can see message exchanging, using `docker logs`. diff --git a/examples/pion-to-pion/answer/Dockerfile b/examples/pion-to-pion/answer/Dockerfile deleted file mode 100644 index ffb3520e6f8..00000000000 --- a/examples/pion-to-pion/answer/Dockerfile +++ /dev/null @@ -1,8 +0,0 @@ -FROM golang:1.20 - -ENV GO111MODULE=on -RUN go install github.com/pion/webrtc/v3/examples/pion-to-pion/answer@latest - -CMD ["answer"] - -EXPOSE 50000 diff --git a/examples/pion-to-pion/answer/main.go b/examples/pion-to-pion/answer/main.go index 84cd39d77ff..79bb1b00d43 100644 --- a/examples/pion-to-pion/answer/main.go +++ b/examples/pion-to-pion/answer/main.go @@ -172,6 +172,10 @@ func main() { // nolint:gocognit // Register text message handling d.OnMessage(func(msg webrtc.DataChannelMessage) { fmt.Printf("Message from DataChannel '%s': '%s'\n", d.Label(), string(msg.Data)) + // make a clean exit on EOF + if string(msg.Data) == "EOF" { + os.Exit(0) + } }) }) diff --git a/examples/pion-to-pion/docker-compose.yml b/examples/pion-to-pion/docker-compose.yml deleted file mode 100644 index fff78574fe0..00000000000 --- a/examples/pion-to-pion/docker-compose.yml +++ /dev/null @@ -1,13 +0,0 @@ -version: '3' -services: - answer: - container_name: answer - build: ./answer - command: answer -offer-address offer:50000 - - offer: - container_name: offer - depends_on: - - answer - build: ./offer - command: offer -answer-address answer:60000 diff --git a/examples/pion-to-pion/offer/Dockerfile b/examples/pion-to-pion/offer/Dockerfile deleted file mode 100644 index 9d13e5983ab..00000000000 --- a/examples/pion-to-pion/offer/Dockerfile +++ /dev/null @@ -1,6 +0,0 @@ -FROM golang:1.20 - -ENV GO111MODULE=on -RUN go install github.com/pion/webrtc/v3/examples/pion-to-pion/offer@latest - -CMD ["offer"] diff --git a/examples/pion-to-pion/offer/main.go b/examples/pion-to-pion/offer/main.go index ef845c9f763..500f2996d4e 100644 --- a/examples/pion-to-pion/offer/main.go +++ b/examples/pion-to-pion/offer/main.go @@ -6,6 +6,7 @@ import ( "flag" "fmt" "io/ioutil" + "math" "net/http" "os" "sync" @@ -32,6 +33,8 @@ func signalCandidate(addr string, c *webrtc.ICECandidate) error { func main() { //nolint:gocognit offerAddr := flag.String("offer-address", ":50000", "Address that the Offer HTTP server is hosted on.") answerAddr := flag.String("answer-address", "127.0.0.1:60000", "Address that the Answer HTTP server is hosted on.") + count := flag.Int("count", math.MaxInt, "Number of messages to send") + wait := flag.Int("wait", 5, "How long to wait between messages") flag.Parse() var candidatesMux sync.Mutex @@ -133,13 +136,28 @@ func main() { //nolint:gocognit } }) + done := make(chan bool) + messagesSent := 0 + // Register channel opening handling dataChannel.OnOpen(func() { - fmt.Printf("Data channel '%s'-'%d' open. Random messages will now be sent to any connected DataChannels every 5 seconds\n", dataChannel.Label(), dataChannel.ID()) + fmt.Printf("Data channel '%s'-'%d' open. Random messages will now be sent to any connected DataChannels every %d seconds\n", dataChannel.Label(), dataChannel.ID(), *wait) + waitDuration := time.Duration(*wait) * time.Second + + for range time.NewTicker(waitDuration).C { + // send EOF for orderly teardown of the session + if messagesSent == *count { + err = dataChannel.SendText("EOF") + if err != nil { + panic(err) + } + done <- true + break + } - for range time.NewTicker(5 * time.Second).C { message := signal.RandSeq(15) fmt.Printf("Sending '%s'\n", message) + messagesSent++ // Send the message as text sendTextErr := dataChannel.SendText(message) @@ -171,13 +189,20 @@ func main() { //nolint:gocognit if err != nil { panic(err) } - resp, err := http.Post(fmt.Sprintf("http://%s/sdp", *answerAddr), "application/json; charset=utf-8", bytes.NewReader(payload)) // nolint:noctx + // retry in case the other side is not yet ready + for i := 0; i < 10; i++ { + resp, postErr := http.Post(fmt.Sprintf("http://%s/sdp", *answerAddr), "application/json; charset=utf-8", bytes.NewReader(payload)) // nolint:noctx + if err = resp.Body.Close(); err != nil { + panic(err) + } + if postErr == nil { + break + } + time.Sleep(3 * time.Second) + } if err != nil { panic(err) - } else if err := resp.Body.Close(); err != nil { - panic(err) } - - // Block forever - select {} + // wait for all sent messages to be received + <-done } diff --git a/examples/pion-to-pion/test.sh b/examples/pion-to-pion/test.sh deleted file mode 100755 index 0ae41c3ddfb..00000000000 --- a/examples/pion-to-pion/test.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash -eu - -docker compose up -d - -function on_exit { - docker compose logs - docker compose rm -fsv -} - -trap on_exit EXIT - -TIMEOUT=10 -timeout $TIMEOUT docker compose logs -f | grep -q "answer | Message from DataChannel" -timeout $TIMEOUT docker compose logs -f | grep -q "offer | Message from DataChannel"