diff --git a/.github/workflows/cypress-nightly.yml b/.github/workflows/cypress-nightly.yml index c2ed3acee..ca7253bf4 100644 --- a/.github/workflows/cypress-nightly.yml +++ b/.github/workflows/cypress-nightly.yml @@ -10,63 +10,37 @@ on: jobs: cypress-tests: - runs-on: [goth2, ubuntu-22.10] + runs-on: goth2 steps: - name: Checkout uses: actions/checkout@v3 - - name: Configure node.js - uses: actions/setup-node@v3 - with: - node-version: 18 + - name: Use random string for subnet + run: echo "YAGNA_SUBNET=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 8 ; echo '')" >> $GITHUB_ENV - - name: Install browsers and graphic environment - run: | - sudo apt-get update -y - sudo apt-get install -y build-essential - sudo apt-get install -y libgtk2.0-0 libgtk-3-0 libgbm-dev libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 libxtst6 xauth xvfb - wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb - sudo apt install --allow-downgrades -y ./google-chrome-stable_current_amd64.deb + - name: Build the docker containers + # Use a random string to avoid other providers on the same subnet which might cause tests to fail because it expects only providers named provider-1 and provider-2 + run: docker compose -f tests/docker/docker-compose.yml build - - name: Build the SDK - run: | - npm install - npm run build + - name: Start the docker containers + # Use a random string to avoid other providers on the same subnet which might cause tests to fail because it expects only providers named provider-1 and provider-2 + run: docker compose -f tests/docker/docker-compose.yml down && docker compose -f tests/docker/docker-compose.yml up -d - - name: Configure python - continue-on-error: true - uses: actions/setup-python@v4 - with: - python-version: "3.10" + - name: Fund the requestor + # Use a funding script which will retry funding the requestor 3 times, else it exits with error. The faucet is not reliable and sometimes fails to fund the requestor, thus the retry. + run: sleep 4 && docker exec -t docker-requestor-1 /bin/sh -c "/golem-js/tests/docker/fundRequestor.sh" - - name: Install goth + - name: Install and build the SDK in the docker container run: | - pip install goth - rm -rf ../goth/assets - python -m goth create-assets ../goth/assets - sed -Ezi 's/(use\-proxy:\s)(True)/\1False/mg' ../goth/assets/goth-config.yml - sed -Ezi 's/(use\-prerelease:\s)(false)/\1true\n release-tag: "0.13.0-rc10"/mg' ../goth/assets/goth-config.yml - sed -i '/^ENTRYPOINT/i ENV YAGNA_AUTOCONF_APPKEY=try_golem' ../goth/assets/docker/yagna-goth-deb.Dockerfile - - - name: Cleanup Docker - if: always() - run: | - c=$(docker ps -q) && [[ $c ]] && docker kill $c - docker system prune -af - - - name: Log in to GitHub Docker repository - run: echo ${{ secrets.GITHUB_TOKEN }} | docker login docker.pkg.github.com -u ${{github.actor}} --password-stdin + docker exec -t docker-requestor-1 /bin/sh -c "cd /golem-js && npm i && npm run build && ./node_modules/.bin/cypress install" - name: Run web server run: | - cd examples/web - node app.mjs & + docker exec -t -d docker-requestor-1 /bin/sh -c "cd /golem-js/examples/web && node app.mjs" - name: Run test suite - env: - GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - npm run test:cypress -- --browser chrome + docker exec -t docker-requestor-1 /bin/sh -c "cd /golem-js && npm run test:cypress -- --browser chromium" - name: Upload test logs uses: actions/upload-artifact@v2 @@ -75,11 +49,6 @@ jobs: name: cypress-logs path: .cypress - # Only relevant for self-hosted runners - - name: Remove test logs - if: always() - run: rm -rf .cypress - - name: Cleanup Docker if: always() run: | diff --git a/.github/workflows/examples-nightly.yml b/.github/workflows/examples-nightly.yml index 4833088ca..fc3245694 100644 --- a/.github/workflows/examples-nightly.yml +++ b/.github/workflows/examples-nightly.yml @@ -21,7 +21,7 @@ jobs: run: echo "::set-output name=matrix::{\"include\":[{\"branch\":\"master\"}]}" goth-tests: - runs-on: [goth2, ubuntu-22.10] + runs-on: goth2 needs: prepare-matrix-master-only strategy: matrix: ${{ fromJson(needs.prepare-matrix-master-only.outputs.matrix-json) }} @@ -31,61 +31,28 @@ jobs: - name: Checkout uses: actions/checkout@v3 - - name: Configure node.js - uses: actions/setup-node@v3 - with: - node-version: 18 + - name: Use random string for subnet + run: echo "YAGNA_SUBNET=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 8 ; echo '')" >> $GITHUB_ENV - - name: Build golem-js - run: | - sudo apt-get update -y - sudo apt-get install -y build-essential - npm install - npm run build - npm install --prefix examples - npm install ts-node + - name: Build the docker containers + # Use a random string to avoid other providers on the same subnet which might cause tests to fail because it expects only providers named provider-1 and provider-2 + run: docker compose -f tests/docker/docker-compose.yml build - - name: Configure python - continue-on-error: true - uses: actions/setup-python@v4 - with: - python-version: "3.10" + - name: Start the docker containers + # Use a random string to avoid other providers on the same subnet which might cause tests to fail because it expects only providers named provider-1 and provider-2 + run: docker compose -f tests/docker/docker-compose.yml down && docker compose -f tests/docker/docker-compose.yml up -d - - name: Install goth - run: | - pip install goth>=0.15.3 - rm -rf ../goth/assets - python -m goth create-assets ../goth/assets - sed -Ezi 's/(use\-proxy:\s)(True)/\1False/mg' ../goth/assets/goth-config.yml - sed -Ezi 's/(use\-prerelease:\s)(false)/\1true\n release-tag: "0.13.0-rc21"/mg' ../goth/assets/goth-config.yml - sed -i '/^ENTRYPOINT/i ENV YAGNA_AUTOCONF_APPKEY=try_golem' ../goth/assets/docker/yagna-goth-deb.Dockerfile + - name: Fund the requestor + # Use a funding script which will retry funding the requestor 3 times, else it exits with error. The faucet is not reliable and sometimes fails to fund the requestor, thus the retry. + run: sleep 4 && docker exec -t docker-requestor-1 /bin/sh -c "/golem-js/tests/docker/fundRequestor.sh" - - name: Cleanup Docker - if: always() + - name: Install and build the SDK in the docker container run: | - c=$(docker ps -q) && [[ $c ]] && docker kill $c - docker system prune -af + docker exec -t docker-requestor-1 /bin/sh -c "cd /golem-js && npm i && npm run build" - - name: Log in to GitHub Docker repository - run: echo ${{ secrets.GITHUB_TOKEN }} | docker login docker.pkg.github.com -u ${{github.actor}} --password-stdin - - - name: Run test suite - env: - GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Run the Examples tests run: | - npm run test:examples - - - name: Upload test logs - uses: actions/upload-artifact@v2 - if: always() - with: - name: goth-logs - path: /tmp/goth-tests - - # Only relevant for self-hosted runners - - name: Remove test logs - if: always() - run: rm -rf /tmp/goth-tests + docker exec -t docker-requestor-1 /bin/sh -c "cd /golem-js && npm install --prefix examples && npm install ts-node && npm run test:examples -- --exitOnError" - name: Cleanup Docker if: always() diff --git a/.github/workflows/goth-nightly.yml b/.github/workflows/goth-nightly.yml index 1106a7b26..daae76ed9 100644 --- a/.github/workflows/goth-nightly.yml +++ b/.github/workflows/goth-nightly.yml @@ -21,7 +21,7 @@ jobs: run: echo "::set-output name=matrix::{\"include\":[{\"branch\":\"master\"}]}" goth-tests: - runs-on: [goth2, ubuntu-22.10] + runs-on: goth2 needs: prepare-matrix-master-only strategy: matrix: ${{ fromJson(needs.prepare-matrix-master-only.outputs.matrix-json) }} @@ -31,64 +31,27 @@ jobs: - name: Checkout uses: actions/checkout@v3 - - name: Configure node.js - uses: actions/setup-node@v3 - with: - node-version: 18 + - name: Use random string for subnet + run: echo "YAGNA_SUBNET=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 8 ; echo '')" >> $GITHUB_ENV - - name: Build golem-js - run: | - sudo apt-get update -y - sudo apt-get install -y build-essential - npm install - npm run build - - - name: Configure python - continue-on-error: true - uses: actions/setup-python@v4 - with: - python-version: "3.10" - - - name: Install goth - run: | - pip install goth - rm -rf ../goth/assets - python -m goth create-assets ../goth/assets - sed -Ezi 's/(use\-proxy:\s)(True)/\1False/mg' ../goth/assets/goth-config.yml - sed -Ezi 's/(use\-prerelease:\s)(false)/\1true\n release-tag: "0.13.0-rc10"/mg' ../goth/assets/goth-config.yml + - name: Build the docker containers + # Use a random string to avoid other providers on the same subnet which might cause tests to fail because it expects only providers named provider-1 and provider-2 + run: docker compose -f tests/docker/docker-compose.yml build - - name: Install websocat and sshpass - run: | - sudo wget https://github.com/vi/websocat/releases/download/v1.9.0/websocat_linux64 -O /usr/local/bin/websocat - sudo chmod +x /usr/local/bin/websocat - sudo apt-get install sshpass - - - name: Cleanup Docker - if: always() - run: | - c=$(docker ps -q) && [[ $c ]] && docker kill $c - docker system prune -af + - name: Start the docker containers + # Use a random string to avoid other providers on the same subnet which might cause tests to fail because it expects only providers named provider-1 and provider-2 + run: docker compose -f tests/docker/docker-compose.yml down && docker compose -f tests/docker/docker-compose.yml up -d - - name: Log in to GitHub Docker repository - run: echo ${{ secrets.GITHUB_TOKEN }} | docker login docker.pkg.github.com -u ${{github.actor}} --password-stdin + - name: Fund the requestor + # Use a funding script which will retry funding the requestor 3 times, else it exits with error. The faucet is not reliable and sometimes fails to fund the requestor, thus the retry. + run: sleep 4 && docker exec -t docker-requestor-1 /bin/sh -c "/golem-js/tests/docker/fundRequestor.sh" - - name: Run test suite - env: - GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Install and build the SDK in the docker container run: | - npm run test:e2e + docker exec -t docker-requestor-1 /bin/sh -c "cd /golem-js && npm i && npm run build" - - name: Upload test logs - uses: actions/upload-artifact@v2 - if: always() - with: - name: goth-logs - path: /tmp/goth-tests - - # Only relevant for self-hosted runners - - name: Remove test logs - if: always() - run: rm -rf /tmp/goth-tests + - name: Start the e2e test + run: docker exec -t docker-requestor-1 /bin/sh -c "cd /golem-js && npm i && npm run test:e2e" - name: Cleanup Docker if: always() diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6f8dc4dce..a73e85f4f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -54,131 +54,53 @@ jobs: - name: Checkout uses: actions/checkout@v3 - - name: Configure NodeJS - uses: actions/setup-node@v3 - with: - # other versions are tested beforehand, so we can keep it short - node-version: 16 - - - name: Install packages required to set-up Goth - run: | - sudo apt-get update -y - sudo apt-get install -y build-essential - - - name: Install browsers and graphic environment for Cypress tests - run: | - sudo apt-get install -y libgtk2.0-0 libgtk-3-0 libgbm-dev libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 libxtst6 xauth xvfb - wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb - sudo apt install -y ./google-chrome-stable_current_amd64.deb + - name: Use random string for subnet + run: echo "YAGNA_SUBNET=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 8 ; echo '')" >> $GITHUB_ENV - - name: Install websocat and sshpass (required by some tests) - run: | - sudo wget https://github.com/vi/websocat/releases/download/v1.9.0/websocat_linux64 -O /usr/local/bin/websocat - sudo chmod +x /usr/local/bin/websocat - sudo apt-get install sshpass - - - name: Build the SDK - run: | - npm install - npm run build - npm install --prefix examples - npm install ts-node + - name: Build the docker containers + # Use a random string to avoid other providers on the same subnet which might cause tests to fail because it expects only providers named provider-1 and provider-2 + run: docker compose -f tests/docker/docker-compose.yml build - - name: Configure python - uses: actions/setup-python@v4 - with: - python-version: "3.9" + - name: Start the docker containers + # Use a random string to avoid other providers on the same subnet which might cause tests to fail because it expects only providers named provider-1 and provider-2 + run: docker compose -f tests/docker/docker-compose.yml down && docker compose -f tests/docker/docker-compose.yml up -d - #region Goth Setup - - name: Install Goth - run: | - pip install goth - rm -rf ../goth/assets - python -m goth create-assets ../goth/assets - sed -Ezi 's/(use\-proxy:\s)(True)/\1False/mg' ../goth/assets/goth-config.yml - sed -Ezi 's/(use\-prerelease:\s)(false)/\1true\n release-tag: "0.13.0-rc10"/mg' ../goth/assets/goth-config.yml - sed -i '/^ENTRYPOINT/i ENV YAGNA_AUTOCONF_APPKEY=try_golem' ../goth/assets/docker/yagna-goth-deb.Dockerfile + - name: Fund the requestor + # Use a funding script which will retry funding the requestor 3 times, else it exits with error. The faucet is not reliable and sometimes fails to fund the requestor, thus the retry. + run: sleep 4 && docker exec -t docker-requestor-1 /bin/sh -c "/golem-js/tests/docker/fundRequestor.sh" - - name: Cleanup Docker - if: always() + - name: Install and build the SDK in the docker container run: | - c=$(docker ps -q) && [[ $c ]] && docker kill $c - docker system prune -af + docker exec -t docker-requestor-1 /bin/sh -c "cd /golem-js && npm i && npm run build && ./node_modules/.bin/cypress install && npm install --prefix examples && npm install ts-node" - - name: Log in to GitHub Docker repository - run: echo ${{ secrets.GITHUB_TOKEN }} | docker login docker.pkg.github.com -u ${{github.actor}} --password-stdin - #endregion - - #region E2E test execution - - name: Run the E2E tests using Goth - env: - GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - npm run test:e2e - - - name: Upload test logs - uses: actions/upload-artifact@v2 - if: always() - with: - name: goth-logs - path: /tmp/goth-tests - - # Only relevant for self-hosted runners - - name: Remove test logs - if: always() - run: rm -rf /tmp/goth-tests - #endregion + - name: Start the e2e test + run: docker exec -t docker-requestor-1 /bin/sh -c "cd /golem-js && npm run test:e2e" #region Cypress test execution - name: Run web server run: | - cd examples/web - node app.mjs & + docker exec -t -d docker-requestor-1 /bin/sh -c "cd /golem-js/examples/web && node app.mjs" - name: Run test suite - env: - GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - npm run test:cypress -- --browser chrome + docker exec -t docker-requestor-1 /bin/sh -c "cd /golem-js && npm run test:cypress -- --browser chromium" - - name: Upload test logs - uses: actions/upload-artifact@v2 - if: always() - with: - name: cypress-logs - path: .cypress - - # Only relevant for self-hosted runners - - name: Remove test logs - if: always() - run: rm -rf .cypress - #endregion - - #region Examples test execution - - name: Run the Examples tests using Goth - env: - GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Run the Examples tests run: | - npm run test:examples + docker exec -t docker-requestor-1 /bin/sh -c "cd /golem-js && npm run test:examples -- --exitOnError" - name: Upload test logs uses: actions/upload-artifact@v2 if: always() with: - name: goth-logs - path: /tmp/goth-tests - - # Only relevant for self-hosted runners - - name: Remove test logs - if: always() - run: rm -rf /tmp/goth-tests + name: cypress-logs + path: .cypress - name: Cleanup Docker if: always() run: | c=$(docker ps -q) && [[ $c ]] && docker kill $c docker system prune -af - #endregion release: name: Release the SDK to NPM and GitHub diff --git a/README.md b/README.md index 2da5a0352..2fe5657a3 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,8 @@ - [Testing](#testing) - [Running unit tests](#running-unit-tests) - [Running E2E tests](#running-e2e-tests) - - [NodeJS](#nodejs) - - [Cypress](#cypress) + - [NodeJS](#execute-the-e2e-tests) + - [Cypress](#execute-the-cypress-tests) - [Contributing](#contributing) - [Controlling interactions and costs](#controlling-interactions-and-costs) - [See also](#see-also) @@ -114,27 +114,69 @@ yarn test:unit ### Running E2E tests Both test cases for the NodeJS environment and the browser (cypress) require preparation of a test environment of the -Golem Network with Providers and all the necessary infrastructure. [Goth](https://github.com/golemfactory/goth) -framework is used for this purpose. +Golem Network with Providers and all the necessary infrastructure. -To enable E2E testing, you need to ensure that `python -m goth` is executable. Therefore, you must first -install [Goth](https://github.com/golemfactory/goth) according to the instructions described in the readme of the -project. +#### Prerequisites -#### NodeJS +1. Ensure you have `docker` and `docker-compose` installed in your system. +2. Your Linux environment should have nested virtualization enabled. -```bash -npm run test:e2e -# or -yarn test:e2e +#### Test Environment Preparation + +Follow these steps to prepare your test environment: + +##### Build Docker Containers + +First, build the Docker containers using the `docker-compose.yml` file located under `tests/docker`. + +Execute this command to build the Docker containers: + + docker compose -f tests/docker/docker-compose.yml build + +##### Start Docker Containers + +Then, launch the Docker containers you've just built using the same `docker-compose.yml` file. + +Execute this command to start the Docker containers: + + docker compose -f tests/docker/docker-compose.yml down && docker compose -f tests/docker/docker-compose.yml up -d + +##### Fund the Requestor + +The next step is to fund the requestor. + + docker exec -t docker-requestor-1 /bin/sh -c "/golem-js/tests/docker/fundRequestor.sh" + +##### Install and Build the SDK + +Finally, install and build the golem-js SDK in the Docker container + +Run this chain of commands to install and build the SDK and prepare cypress. + +```docker +docker exec -t docker-requestor-1 /bin/sh -c "cd /golem-js && npm i && npm run build && ./node_modules/.bin/cypress install" ``` -#### Cypress +#### Execute the E2E Tests -```bash -npm run test:cypress -# or -yarn test:cypress +With your test environment set up, you can now initiate the E2E tests. Run the following command to start: + +```docker +docker exec -t docker-requestor-1 /bin/sh -c "cd /golem-js && npm run test:e2e" +``` + +#### Execute the cypress Tests + +First make sure that the webserver that's used for testing is running, by running the command + +```docker +docker exec -t -d docker-requestor-1 /bin/sh -c "cd /golem-js/examples/web && node app.mjs" +``` + +Now you're ready to start the cypress tests by running the command + +```docker +docker exec -t docker-requestor-1 /bin/sh -c "cd /golem-js && npm run test:cypress -- --browser chromium" ``` ### Contributing diff --git a/cypress.config.ts b/cypress.config.ts index f76baf63e..4ce809e49 100644 --- a/cypress.config.ts +++ b/cypress.config.ts @@ -1,9 +1,4 @@ import { defineConfig } from "cypress"; -import { Goth } from "./tests/goth/goth"; -import { resolve } from "path"; - -const gothConfig = resolve("../goth/assets/goth-config.yml"); -const goth = new Goth(gothConfig); export default defineConfig({ fileServerFolder: "examples/web", @@ -11,7 +6,7 @@ export default defineConfig({ fixturesFolder: "tests/cypress/fixtures", videosFolder: ".cypress/video", screenshotsFolder: ".cypress/screenshots", - defaultCommandTimeout: 90000, + defaultCommandTimeout: 180000, experimentalInteractiveRunEvents: true, chromeWebSecurity: false, video: true, @@ -20,14 +15,10 @@ export default defineConfig({ supportFile: "tests/cypress/support/e2e.ts", specPattern: "tests/cypress/ui/**/*.cy.ts", setupNodeEvents(on, config) { - on("after:run", async () => { - await goth.end(); - }); return new Promise(async (res) => { - const { apiKey, basePath, subnetTag } = await goth.start(); - config.env.YAGNA_APPKEY = apiKey; - config.env.YAGNA_API_BASEPATH = basePath; - config.env.YAGNA_SUBNET = subnetTag; + config.env.YAGNA_APPKEY = process.env.YAGNA_APPKEY; + config.env.YAGNA_API_BASEPATH = process.env.YAGNA_API_URL; + config.env.YAGNA_SUBNET = process.env.YAGNA_SUBNET; res(config); }); }, diff --git a/examples/docs-examples/examples/selecting-providers/whitelist.mjs b/examples/docs-examples/examples/selecting-providers/whitelist.mjs index 26bdcd6fe..120ad157a 100644 --- a/examples/docs-examples/examples/selecting-providers/whitelist.mjs +++ b/examples/docs-examples/examples/selecting-providers/whitelist.mjs @@ -1,31 +1,24 @@ import { TaskExecutor, ProposalFilters } from "@golem-sdk/golem-js"; /** - * Example demonstrating how to use the predefined filter `whiteListProposalIdsFilter`, - * which only allows offers from a provider whose ID is in the array + * Example demonstrating how to use the predefined filter `whiteListProposalNamesFilter`, + * which only allows offers from a provider whose name is in the array */ -const whiteListIds = [ - "0x3a21c608925ddbc745afab6375d1f5e77283538e", - "0xd79f83f1108d1fcbe0cf57e13b452305eb38a325", - "0x677c5476f3b0e1f03d5c3abd2e2e2231e36fddde", - "0x06c03165aaa676680b9d02c1f3ee846c3806fec7", - "0x17ec8597ff92c3f44523bdc65bf0f1be632917ff", // goth provider-1: - "0x63fc2ad3d021a4d7e64323529a55a9442c444da0", // goth provider-2: -]; +const whiteListNames = ["provider-2", "fractal_01_3.h", "sharkoon_379_0.h", "fractal_01_1.h", "sharkoon_379_1.h"]; console.log("Will accept only proposals from:"); -for (let i = 0; i < whiteListIds.length; i++) { - console.log(whiteListIds[i]); +for (let i = 0; i < whiteListNames.length; i++) { + console.log(whiteListNames[i]); } (async function main() { const executor = await TaskExecutor.create({ package: "9a3b5d67b0b27746283cb5f287c13eab1beaa12d92a9f536b747c7ae", - proposalFilter: ProposalFilters.whiteListProposalIdsFilter(whiteListIds), + proposalFilter: ProposalFilters.whiteListProposalNamesFilter(whiteListNames), yagnaOptions: { apiKey: "try_golem" }, }); await executor.run(async (ctx) => - console.log((await ctx.run(`echo "This task is run on ${ctx.provider.id}"`)).stdout, ctx.provider.id), + console.log((await ctx.run(`echo "This task is run on ${ctx.provider.name}"`)).stdout, ctx.provider.name), ); await executor.end(); })(); diff --git a/package.json b/package.json index f47fd040d..39eb36eb4 100644 --- a/package.json +++ b/package.json @@ -27,10 +27,8 @@ "test": "npm run test:unit && npm run test:e2e", "test:unit": "jest --config tests/unit/jest.config.json", "test:e2e": "jest --config tests/e2e/jest.config.json tests/e2e/**.spec.ts --runInBand --forceExit", - "test:e2e:no-goth": "jest tests/e2e/**.spec.ts --testTimeout=180000 --runInBand --forceExit", "test:cypress": "cypress run", "test:examples": "ts-node --project tsconfig.spec.json tests/examples/examples.test.ts", - "test:examples:no-goth": "ts-node --project tsconfig.spec.json tests/examples/examples.test.ts --no-goth", "lint": "npm run lint:ts && npm run lint:ts:tests && npm run lint:eslint", "lint:ts": "tsc --project tsconfig.json --noEmit", "lint:ts:tests": "tsc --project tests/tsconfig.json --noEmit", diff --git a/tests/docker/Provider.Dockerfile b/tests/docker/Provider.Dockerfile new file mode 100644 index 000000000..81ee1c94d --- /dev/null +++ b/tests/docker/Provider.Dockerfile @@ -0,0 +1,41 @@ +ARG UBUNTU_VERSION=22.04 +ARG YA_CORE_VERSION=0.12.3 +ARG YA_WASI_VERSION=0.2.2 +ARG YA_VM_VERSION=0.3.0 + +FROM ubuntu:${UBUNTU_VERSION} +ARG YA_CORE_VERSION +ARG YA_WASI_VERSION +ARG YA_VM_VERSION +ARG YA_DIR_INSTALLER=/ya-installer +ARG YA_DIR_BIN=/usr/bin +ARG YA_DIR_PLUGINS=/lib/yagna/plugins +COPY /data-node/ya-provider/ /root/.local/share/ya-provider/ +RUN apt-get update -q \ + && apt-get install -q -y --no-install-recommends \ + wget \ + apt-transport-https \ + ca-certificates \ + xz-utils \ + curl \ + python3 \ + && apt-get remove --purge -y \ + && apt-get clean -y \ + && rm -rf /var/lib/apt/lists/* \ + && mkdir -p ${YA_DIR_PLUGINS} \ + && mkdir ${YA_DIR_INSTALLER} \ + && cd ${YA_DIR_INSTALLER} \ + && wget -q "https://github.com/golemfactory/yagna/releases/download/v${YA_CORE_VERSION}/golem-provider-linux-v${YA_CORE_VERSION}.tar.gz" \ + && wget -q "https://github.com/golemfactory/ya-runtime-wasi/releases/download/v${YA_WASI_VERSION}/ya-runtime-wasi-linux-v${YA_WASI_VERSION}.tar.gz" \ + && wget -q "https://github.com/golemfactory/ya-runtime-vm/releases/download/v${YA_VM_VERSION}/ya-runtime-vm-linux-v${YA_VM_VERSION}.tar.gz" \ + && tar -zxvf golem-provider-linux-v${YA_CORE_VERSION}.tar.gz \ + && tar -zxvf ya-runtime-wasi-linux-v${YA_WASI_VERSION}.tar.gz \ + && tar -zxvf ya-runtime-vm-linux-v${YA_VM_VERSION}.tar.gz \ + && find golem-provider-linux-v${YA_CORE_VERSION} -executable -type f -exec cp {} ${YA_DIR_BIN} \; \ + && cp -R golem-provider-linux-v${YA_CORE_VERSION}/plugins/* ${YA_DIR_PLUGINS} \ + && cp -R ya-runtime-wasi-linux-v${YA_WASI_VERSION}/* ${YA_DIR_PLUGINS} \ + && cp -R ya-runtime-vm-linux-v${YA_VM_VERSION}/* ${YA_DIR_PLUGINS} \ + && rm -Rf ${YA_DIR_INSTALLER} +COPY ./configureProvider.py /configureProvider.py + +CMD ["bash", "-c", "python3 /configureProvider.py && golemsp run --payment-network testnet"] diff --git a/tests/docker/Requestor.Dockerfile b/tests/docker/Requestor.Dockerfile new file mode 100644 index 000000000..b64167fdd --- /dev/null +++ b/tests/docker/Requestor.Dockerfile @@ -0,0 +1,44 @@ +ARG UBUNTU_VERSION=22.04 +ARG YA_CORE_VERSION=0.13.0-rc10 + +FROM node:18 +ARG YA_CORE_VERSION +ARG YA_DIR_INSTALLER=/ya-installer +ARG YA_DIR_BIN=/usr/bin +RUN apt-get update -q \ + && apt-get install -q -y --no-install-recommends \ + wget \ + apt-transport-https \ + ca-certificates \ + xz-utils \ + curl \ + sshpass \ + python3 \ + libgtk2.0-0 \ + libgtk-3-0 \ + libgbm-dev \ + libnotify-dev \ + libgconf-2-4 \ + libnss3 \ + libxss1 \ + libasound2 \ + libxtst6 \ + xauth \ + xvfb \ + chromium \ + && apt-get remove --purge -y \ + && apt-get clean -y \ + && rm -rf /var/lib/apt/lists/* \ + && mkdir ${YA_DIR_INSTALLER} \ + && cd ${YA_DIR_INSTALLER} \ + && wget -q "https://github.com/golemfactory/yagna/releases/download/pre-rel-v${YA_CORE_VERSION}/golem-requestor-linux-pre-rel-v${YA_CORE_VERSION}.tar.gz" \ + && tar -zxvf golem-requestor-linux-pre-rel-v${YA_CORE_VERSION}.tar.gz \ + && find golem-requestor-linux-pre-rel-v${YA_CORE_VERSION} -executable -type f -exec cp {} ${YA_DIR_BIN} \; \ + && rm -Rf ${YA_DIR_INSTALLER} \ + && wget -O ${YA_DIR_BIN}/websocat "https://github.com/vi/websocat/releases/download/v1.12.0/websocat_max.x86_64-unknown-linux-musl" \ + && chmod +x ${YA_DIR_BIN}/websocat + + +COPY ./startRequestor.sh /startRequestor.sh + +CMD ["bash", "-c", "/startRequestor.sh"] diff --git a/tests/docker/configureProvider.py b/tests/docker/configureProvider.py new file mode 100644 index 000000000..ccd452297 --- /dev/null +++ b/tests/docker/configureProvider.py @@ -0,0 +1,20 @@ +import os +import json + + +def update_globals(file_path, node_name): + try: + with open(file_path, 'r+') as f: + data = json.load(f) + data['node_name'] = node_name + f.seek(0) + print(data) + json.dumps(data, f) + f.truncate() + print(f"Provider node name configured to {node_name}") + except Exception as e: + print(f"Error occurred: {str(e)}") + + +update_globals(os.path.expanduser( + '/root/.local/share/ya-provider/globals.json'), os.environ.get('NODE_NAME')) diff --git a/tests/docker/data-node/ya-provider/globals.json b/tests/docker/data-node/ya-provider/globals.json new file mode 100644 index 000000000..83261dce1 --- /dev/null +++ b/tests/docker/data-node/ya-provider/globals.json @@ -0,0 +1,5 @@ +{ + "node_name": "node-name", + "subnet": "public", + "account": "0x797cE3Aa8dc255D13E48F31A6B23fe18b5924940" +} diff --git a/tests/docker/data-node/ya-provider/hardware.json b/tests/docker/data-node/ya-provider/hardware.json new file mode 100644 index 000000000..51f668a89 --- /dev/null +++ b/tests/docker/data-node/ya-provider/hardware.json @@ -0,0 +1,10 @@ +{ + "active": "default", + "profiles": { + "default": { + "cpu_threads": 1, + "mem_gib": 2.0, + "storage_gib": 10.0 + } + } +} diff --git a/tests/docker/data-node/ya-provider/presets.json b/tests/docker/data-node/ya-provider/presets.json new file mode 100644 index 000000000..e360c9cb2 --- /dev/null +++ b/tests/docker/data-node/ya-provider/presets.json @@ -0,0 +1,35 @@ +{ + "active": ["wasmtime", "vm"], + "presets": [ + { + "name": "default", + "exeunit-name": "wasmtime", + "pricing-model": "linear", + "usage-coeffs": { + "cpu": 0.500000001, + "duration": 0.0, + "initial": 0.0 + } + }, + { + "name": "vm", + "exeunit-name": "vm", + "pricing-model": "linear", + "usage-coeffs": { + "cpu": 0.500000001, + "duration": 0.0, + "initial": 0.0 + } + }, + { + "name": "wasmtime", + "exeunit-name": "wasmtime", + "pricing-model": "linear", + "usage-coeffs": { + "cpu": 0.500000001, + "duration": 0.0, + "initial": 0.0 + } + } + ] +} diff --git a/tests/docker/docker-compose.yml b/tests/docker/docker-compose.yml new file mode 100644 index 000000000..aa38e11f1 --- /dev/null +++ b/tests/docker/docker-compose.yml @@ -0,0 +1,69 @@ +version: "3.5" +services: + provider-1: + build: + context: . + dockerfile: Provider.Dockerfile + image: provider:latest + restart: always + deploy: + replicas: 6 + volumes: + - /etc/localtime:/etc/localtime:ro + - /root/.local/share/yagna/ + devices: + - /dev/kvm:/dev/kvm + healthcheck: + test: ["CMD-SHELL", "curl -s -o /dev/null -w '%{http_code}' http://localhost:7465 | grep -q 401"] + interval: 10s + timeout: 5s + retries: 1 + start_period: 40s + environment: + - NODE_NAME=provider-1 + - SUBNET=${YAGNA_SUBNET:-golemjstest} + provider-2: + build: + context: . + dockerfile: Provider.Dockerfile + image: provider:latest + restart: always + deploy: + replicas: 6 + volumes: + - /etc/localtime:/etc/localtime:ro + - /root/.local/share/yagna/ + devices: + - /dev/kvm:/dev/kvm + healthcheck: + test: ["CMD-SHELL", "curl -s -o /dev/null -w '%{http_code}' http://localhost:7465 | grep -q 401"] + interval: 10s + timeout: 5s + retries: 1 + start_period: 40s + environment: + - NODE_NAME=provider-2 + - SUBNET=${YAGNA_SUBNET:-golemjstest} + requestor: + build: + context: . + dockerfile: Requestor.Dockerfile + image: requestor:latest + restart: always + volumes: + - /etc/localtime:/etc/localtime:ro + - /root/.local/share/yagna/ + - ../../:/golem-js + environment: + - YAGNA_AUTOCONF_APPKEY=try_golem + - YAGNA_API_URL=http://0.0.0.0:7465 + - GSB_URL=tcp://0.0.0.0:7464 + - YAGNA_SUBNET=${YAGNA_SUBNET:-golemjstest} + - YAGNA_APPKEY=try_golem + + healthcheck: + test: ["CMD-SHELL", "curl -s -o /dev/null -w '%{http_code}' http://localhost:7465 | grep -q 401"] + interval: 10s + timeout: 5s + retries: 1 + start_period: 40s diff --git a/tests/docker/fundRequestor.sh b/tests/docker/fundRequestor.sh new file mode 100755 index 000000000..e1c24e1fb --- /dev/null +++ b/tests/docker/fundRequestor.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +for i in {1..3}; do + yagna payment fund && exit 0 +done + +echo "yagna payment fund failed" >&2 +exit 1 \ No newline at end of file diff --git a/tests/docker/startRequestor.sh b/tests/docker/startRequestor.sh new file mode 100755 index 000000000..d77cf281f --- /dev/null +++ b/tests/docker/startRequestor.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +get_funds_from_faucet() { + echo "Sending request to the faucet" + yagna payment fund +} +echo "Starting Yagna" +yagna service run --api-allow-origin="*" diff --git a/tests/e2e/_setup.ts b/tests/e2e/_setup.ts deleted file mode 100644 index de9ff4749..000000000 --- a/tests/e2e/_setup.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Goth } from "../goth/goth"; -import { resolve } from "path"; - -const timeoutPromise = (seconds: number) => - new Promise((_resolve, reject) => { - setTimeout( - () => reject(new Error(`The timeout was reached and the racing promise has rejected after ${seconds} seconds`)), - seconds * 1000, - ); - }); - -export default async function setUpGoth() { - const gothConfig = resolve("../goth/assets/goth-config.yml"); - globalThis.__GOTH = new Goth(gothConfig); - - // Start Goth, but don't wait for an eternity - return await Promise.race([globalThis.__GOTH.start(), timeoutPromise(180)]); -} diff --git a/tests/e2e/_teardown.ts b/tests/e2e/_teardown.ts deleted file mode 100644 index 994401c50..000000000 --- a/tests/e2e/_teardown.ts +++ /dev/null @@ -1,3 +0,0 @@ -export default async function tearDownGoth() { - await globalThis.__GOTH.end(); -} diff --git a/tests/e2e/jest.config.json b/tests/e2e/jest.config.json index ae00deaa5..8eb5939a8 100644 --- a/tests/e2e/jest.config.json +++ b/tests/e2e/jest.config.json @@ -1,8 +1,6 @@ { "preset": "ts-jest", "testEnvironment": "node", - "globalSetup": "/_setup.ts", - "globalTeardown": "/_teardown.ts", "setupFilesAfterEnv": ["/_setupLogging.ts"], "testTimeout": 180000 } diff --git a/tests/examples/examples.json b/tests/examples/examples.json index 688cc6718..39f7bc056 100644 --- a/tests/examples/examples.json +++ b/tests/examples/examples.json @@ -29,8 +29,6 @@ { "cmd": "node", "path": "examples/docs-examples/examples/sending-data/uploading-file.mjs" }, { "cmd": "node", "path": "examples/docs-examples/examples/sending-data/uploading-json.mjs" }, - { "cmd": "node", "path": "examples/docs-examples/examples/switching-to-mainnet/run-on-polygon.mjs", "noGoth": true }, - { "cmd": "node", "path": "examples/docs-examples/examples/transferring-data/download-file.mjs" }, { "cmd": "node", "path": "examples/docs-examples/examples/transferring-data/upload-file.mjs" }, { "cmd": "node", "path": "examples/docs-examples/examples/transferring-data/upload-json.mjs" }, @@ -62,6 +60,6 @@ "cmd": "node", "path": "examples/docs-examples/tutorials/running-parallel-tasks/index.mjs", "args": ["--mask", "?a?a", "--hash", "$P$5ZDzPE45CigTC6EY4cXbyJSLj/pGee0"], - "timeout": 500 + "timeout": 1000 } ] diff --git a/tests/examples/examples.test.ts b/tests/examples/examples.test.ts index e61e534b2..3e30cfe3e 100644 --- a/tests/examples/examples.test.ts +++ b/tests/examples/examples.test.ts @@ -1,15 +1,8 @@ import { spawn } from "child_process"; import { dirname, basename, resolve } from "path"; -import { Goth } from "../goth/goth"; import chalk from "chalk"; import testExamples from "./examples.json"; -const noGoth = process.argv[2] === "--no-goth"; -const gothConfig = resolve("../goth/assets/goth-config.yml"); -const gothStartingTimeout = 180; -const goth = new Goth(gothConfig); - -const examples = !noGoth ? testExamples.filter((e) => !e?.noGoth) : testExamples; const criticalLogsRegExp = [/Task *. timeot/, /Task *. has been rejected/, /ERROR: TypeError/, /ERROR: Error/gim]; type Example = { @@ -17,11 +10,12 @@ type Example = { path: string; args?: string[]; timeout?: number; - noGoth?: boolean; skip?: boolean; }; -async function test(cmd: string, path: string, args: string[] = [], timeout = 180) { +const exitOnError = process.argv.includes("--exitOnError"); + +async function test(cmd: string, path: string, args: string[] = [], timeout = 360) { const file = basename(path); const cwd = dirname(path); const spawnedExample = spawn(cmd, [file, ...args], { cwd }); @@ -62,16 +56,6 @@ async function test(cmd: string, path: string, args: string[] = [], timeout = 18 async function testAll(examples: Example[]) { const failedTests = new Set(); const skippedTests = new Set(); - if (!noGoth) - await Promise.race([ - goth.start(), - new Promise((res, rej) => - setTimeout( - () => rej(new Error(`The Goth starting timeout was reached after ${gothStartingTimeout} seconds`)), - gothStartingTimeout * 1000, - ), - ), - ]); for (const example of examples) { try { console.log(chalk.yellow(`\n---- Starting test: "${example.path}" ----\n`)); @@ -84,10 +68,13 @@ async function testAll(examples: Example[]) { } } catch (error) { console.log(chalk.bgRed.white(" FAIL "), chalk.red(error)); + if (exitOnError) { + console.log(chalk.bold.red(`\nExiting due to error in: "${example.path}"\n`)); + process.exit(1); + } failedTests.add(example.path); } } - if (!noGoth) await goth.end().catch((error) => console.error(error)); console.log( chalk.bold.yellow("\n\nTESTS RESULTS: "), chalk.bgGreen.black(` ${examples.length - failedTests.size - skippedTests.size} passed `), @@ -102,4 +89,4 @@ async function testAll(examples: Example[]) { process.exit(failedTests.size > 0 ? 1 : 0); } -testAll(examples).then(); +testAll(testExamples).then(); diff --git a/tests/goth/goth.ts b/tests/goth/goth.ts deleted file mode 100644 index 8fea42ca4..000000000 --- a/tests/goth/goth.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { ChildProcess, spawn } from "child_process"; - -type EnvironmentSettings = { apiKey: string; basePath: string; subnetTag: string; gsbUrl: string; path: string }; - -export class Goth { - private gothProcess?: ChildProcess; - - constructor(private readonly gothConfig) {} - - async start(): Promise { - return new Promise((resolve, reject) => { - const startTime = Date.now(); - console.log("\x1b[33mStarting goth process..."); - console.log("\x1b[33mRun command:\x1b[0m \x1b[36m", `python -m goth start ${this.gothConfig}`); - this.gothProcess = spawn("python", ["-m", "goth", "start", this.gothConfig], { - env: { ...process.env, PYTHONUNBUFFERED: "1" }, - }); - this.gothProcess.on("spawn", () => console.log("Goth spawned successfully")); - this.gothProcess?.stdout?.setEncoding("utf-8"); - this.gothProcess?.stderr?.setEncoding("utf-8"); - - this.gothProcess?.stdout?.on("data", (data) => { - const regexp = - /YAGNA_APPKEY=(\w+) YAGNA_API_URL=(http:\/\/127\.0{0,3}\.0{0,3}.0{0,2}1:\d+) GSB_URL=(tcp:\/\/\d+\.\d+\.\d+\.\d+:\d+) PATH=(.*) YAGNA_SUBNET=(\w+)/g; - const results = Array.from(data?.toString()?.matchAll(regexp) || [])?.pop(); - const apiKey = results?.[1]; - const basePath = results?.[2]; - const gsbUrl = results?.[3]; - const path = results?.[4]?.split(":")?.shift(); - const subnetTag = results?.[5]; - if (apiKey) { - process.env["YAGNA_APPKEY"] = apiKey; - process.env["YAGNA_API_URL"] = basePath; - process.env["GSB_URL"] = gsbUrl; - process.env["PATH"] = `${path}:${process.env["PATH"]}`; - process.env["YAGNA_SUBNET"] = subnetTag; - - const settings = { apiKey, basePath, subnetTag, gsbUrl, path }; - - console.log( - `\x1b[33mGoth has been successfully started in ${((Date.now() - startTime) / 1000).toFixed( - 0, - )}s. Resulting settings:`, - settings, - ); - - resolve(settings); - } - }); - this.gothProcess?.stderr?.on("data", (data) => { - if (data.toString().match(/error/)) reject(data); - const regexp = /\[requestor] Gftp volume ([a-zA-Z0-9/_]*)/g; - const results = Array.from(data?.toString()?.matchAll(regexp) || [])?.pop(); - const gftpVolume = results?.[1]; - if (gftpVolume) process.env["GOTH_GFTP_VOLUME"] = gftpVolume + "/out/"; - console.log("\x1b[33m[goth]\x1b[0m " + data.replace(/[\n\t\r]/g, "")); - }); - this.gothProcess.on("error", (error) => reject("Failed to spawn Goth" + error.toString())); - this.gothProcess.on("close", (code) => console.info(`Goth process exit with code ${code}`)); - this.gothProcess.on("exit", (code) => console.info(`Goth process exit with code ${code}`)); - }); - } - - async end() { - this.gothProcess?.kill("SIGINT"); - return new Promise((resolve) => { - this.gothProcess?.on("close", () => { - this.gothProcess?.stdout?.removeAllListeners(); - this.gothProcess?.stderr?.removeAllListeners(); - this.gothProcess?.removeAllListeners(); - console.log(`\x1b[33mGoth has been terminated`); - resolve(); - }); - }); - } -}