diff --git a/.github/workflows/jobs.yaml b/.github/workflows/jobs.yaml index 8ba8b5ba1..bff561d41 100644 --- a/.github/workflows/jobs.yaml +++ b/.github/workflows/jobs.yaml @@ -1348,8 +1348,8 @@ jobs: run: | make cleanup-permissions - all-operator-tests: - name: Operator UI Tests + all-operator-tests-1: + name: Operator UI Tests Part 1 needs: - lint-job - no-warnings-and-make-assets @@ -1440,7 +1440,383 @@ jobs: - name: Run TestCafe Tests uses: DevExpress/testcafe-action@latest with: - args: '"chrome:headless" portal-ui/tests/operator/ --skip-js-errors -c 3' + args: '"chrome:headless" portal-ui/tests/operator/login --skip-js-errors -c 3' + + all-operator-tests-2: + name: Operator UI Tests Part 2 + needs: + - lint-job + - no-warnings-and-make-assets + - reuse-golang-dependencies + - vulnerable-dependencies-checks + - semgrep-static-code-analysis + runs-on: ${{ matrix.os }} + strategy: + matrix: + go-version: [ 1.18.x ] + os: [ ubuntu-latest ] + steps: + - name: Set up Go ${{ matrix.go-version }} on ${{ matrix.os }} + uses: actions/setup-go@v2 + with: + go-version: ${{ matrix.go-version }} + id: go + + - name: Check out code into the Go module directory + uses: actions/checkout@v2 + + # To build operator image, we need to clone the repository first + - name: clone https://github.com/minio/operator + uses: actions/checkout@master + with: + + # Repository name with owner. For example, actions/checkout + # Default: ${{ github.repository }} + repository: minio/operator + + # Relative path under $GITHUB_WORKSPACE to place the repository + # To have two repositories under the same test + path: 'operator_repository' + + - name: Read .nvmrc + id: node_version + run: echo ::set-output name=NVMRC::$(cat .nvmrc) + + - uses: actions/setup-node@v2 + with: + node-version: ${{ env.NVMRC }} + + - uses: actions/cache@v2 + name: Go Mod Cache + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ github.run_id }} + + - name: Get yarn cache directory path + id: yarn-cache-dir-path + run: echo "::set-output name=dir::$(yarn cache dir)" + + - uses: actions/cache@v2 + id: yarn-cache + name: Yarn Cache + with: + path: | + ${{ steps.yarn-cache-dir-path.outputs.dir }} + ./portal-ui/node_modules/ + key: ${{ runner.os }}-yarn-${{ hashFiles('./portal-ui/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + + - uses: actions/cache@v2 + id: assets-cache + name: Assets Cache + with: + path: | + ./portal-ui/build/ + key: ${{ runner.os }}-assets-${{ github.run_id }} + restore-keys: | + ${{ runner.os }}-assets- + + - name: Build Console on ${{ matrix.os }} + env: + GO111MODULE: on + GOOS: linux + run: | + make console + + # Runs a set of commands using the runners shell + - name: Start Kind for Operator UI + run: | + "${GITHUB_WORKSPACE}/portal-ui/tests/scripts/operator.sh" + + - name: Run TestCafe Tests + uses: DevExpress/testcafe-action@latest + with: + args: '"chrome:headless" portal-ui/tests/operator/tenant/test-1 --skip-js-errors -c 3' + + all-operator-tests-3: + name: Operator UI Tests Part 3 + needs: + - lint-job + - no-warnings-and-make-assets + - reuse-golang-dependencies + - vulnerable-dependencies-checks + - semgrep-static-code-analysis + runs-on: ${{ matrix.os }} + strategy: + matrix: + go-version: [ 1.18.x ] + os: [ ubuntu-latest ] + steps: + - name: Set up Go ${{ matrix.go-version }} on ${{ matrix.os }} + uses: actions/setup-go@v2 + with: + go-version: ${{ matrix.go-version }} + id: go + + - name: Check out code into the Go module directory + uses: actions/checkout@v2 + + # To build operator image, we need to clone the repository first + - name: clone https://github.com/minio/operator + uses: actions/checkout@master + with: + + # Repository name with owner. For example, actions/checkout + # Default: ${{ github.repository }} + repository: minio/operator + + # Relative path under $GITHUB_WORKSPACE to place the repository + # To have two repositories under the same test + path: 'operator_repository' + + - name: Read .nvmrc + id: node_version + run: echo ::set-output name=NVMRC::$(cat .nvmrc) + + - uses: actions/setup-node@v2 + with: + node-version: ${{ env.NVMRC }} + + - uses: actions/cache@v2 + name: Go Mod Cache + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ github.run_id }} + + - name: Get yarn cache directory path + id: yarn-cache-dir-path + run: echo "::set-output name=dir::$(yarn cache dir)" + + - uses: actions/cache@v2 + id: yarn-cache + name: Yarn Cache + with: + path: | + ${{ steps.yarn-cache-dir-path.outputs.dir }} + ./portal-ui/node_modules/ + key: ${{ runner.os }}-yarn-${{ hashFiles('./portal-ui/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + + - uses: actions/cache@v2 + id: assets-cache + name: Assets Cache + with: + path: | + ./portal-ui/build/ + key: ${{ runner.os }}-assets-${{ github.run_id }} + restore-keys: | + ${{ runner.os }}-assets- + + - name: Build Console on ${{ matrix.os }} + env: + GO111MODULE: on + GOOS: linux + run: | + make console + + # Runs a set of commands using the runners shell + - name: Start Kind for Operator UI + run: | + "${GITHUB_WORKSPACE}/portal-ui/tests/scripts/operator.sh" + + - name: Run TestCafe Tests + uses: DevExpress/testcafe-action@latest + with: + args: '"chrome:headless" portal-ui/tests/operator/tenant/test-2 --skip-js-errors -c 3' + + all-operator-tests-4: + name: Operator UI Tests Part 4 + needs: + - lint-job + - no-warnings-and-make-assets + - reuse-golang-dependencies + - vulnerable-dependencies-checks + - semgrep-static-code-analysis + runs-on: ${{ matrix.os }} + strategy: + matrix: + go-version: [ 1.18.x ] + os: [ ubuntu-latest ] + steps: + - name: Set up Go ${{ matrix.go-version }} on ${{ matrix.os }} + uses: actions/setup-go@v2 + with: + go-version: ${{ matrix.go-version }} + id: go + + - name: Check out code into the Go module directory + uses: actions/checkout@v2 + + # To build operator image, we need to clone the repository first + - name: clone https://github.com/minio/operator + uses: actions/checkout@master + with: + + # Repository name with owner. For example, actions/checkout + # Default: ${{ github.repository }} + repository: minio/operator + + # Relative path under $GITHUB_WORKSPACE to place the repository + # To have two repositories under the same test + path: 'operator_repository' + + - name: Read .nvmrc + id: node_version + run: echo ::set-output name=NVMRC::$(cat .nvmrc) + + - uses: actions/setup-node@v2 + with: + node-version: ${{ env.NVMRC }} + + - uses: actions/cache@v2 + name: Go Mod Cache + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ github.run_id }} + + - name: Get yarn cache directory path + id: yarn-cache-dir-path + run: echo "::set-output name=dir::$(yarn cache dir)" + + - uses: actions/cache@v2 + id: yarn-cache + name: Yarn Cache + with: + path: | + ${{ steps.yarn-cache-dir-path.outputs.dir }} + ./portal-ui/node_modules/ + key: ${{ runner.os }}-yarn-${{ hashFiles('./portal-ui/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + + - uses: actions/cache@v2 + id: assets-cache + name: Assets Cache + with: + path: | + ./portal-ui/build/ + key: ${{ runner.os }}-assets-${{ github.run_id }} + restore-keys: | + ${{ runner.os }}-assets- + + - name: Build Console on ${{ matrix.os }} + env: + GO111MODULE: on + GOOS: linux + run: | + make console + + # Runs a set of commands using the runners shell + - name: Start Kind for Operator UI + run: | + "${GITHUB_WORKSPACE}/portal-ui/tests/scripts/operator.sh" + + - name: Run TestCafe Tests + uses: DevExpress/testcafe-action@latest + with: + args: '"chrome:headless" portal-ui/tests/operator/tenant/test-3 --skip-js-errors -c 3' + + all-operator-tests-5: + name: Operator UI Tests Part 5 + needs: + - lint-job + - no-warnings-and-make-assets + - reuse-golang-dependencies + - vulnerable-dependencies-checks + - semgrep-static-code-analysis + runs-on: ${{ matrix.os }} + strategy: + matrix: + go-version: [ 1.18.x ] + os: [ ubuntu-latest ] + steps: + - name: Set up Go ${{ matrix.go-version }} on ${{ matrix.os }} + uses: actions/setup-go@v2 + with: + go-version: ${{ matrix.go-version }} + id: go + + - name: Check out code into the Go module directory + uses: actions/checkout@v2 + + # To build operator image, we need to clone the repository first + - name: clone https://github.com/minio/operator + uses: actions/checkout@master + with: + + # Repository name with owner. For example, actions/checkout + # Default: ${{ github.repository }} + repository: minio/operator + + # Relative path under $GITHUB_WORKSPACE to place the repository + # To have two repositories under the same test + path: 'operator_repository' + + - name: Read .nvmrc + id: node_version + run: echo ::set-output name=NVMRC::$(cat .nvmrc) + + - uses: actions/setup-node@v2 + with: + node-version: ${{ env.NVMRC }} + + - uses: actions/cache@v2 + name: Go Mod Cache + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ github.run_id }} + + - name: Get yarn cache directory path + id: yarn-cache-dir-path + run: echo "::set-output name=dir::$(yarn cache dir)" + + - uses: actions/cache@v2 + id: yarn-cache + name: Yarn Cache + with: + path: | + ${{ steps.yarn-cache-dir-path.outputs.dir }} + ./portal-ui/node_modules/ + key: ${{ runner.os }}-yarn-${{ hashFiles('./portal-ui/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + + - uses: actions/cache@v2 + id: assets-cache + name: Assets Cache + with: + path: | + ./portal-ui/build/ + key: ${{ runner.os }}-assets-${{ github.run_id }} + restore-keys: | + ${{ runner.os }}-assets- + + - name: Build Console on ${{ matrix.os }} + env: + GO111MODULE: on + GOOS: linux + run: | + make console + + # Runs a set of commands using the runners shell + - name: Start Kind for Operator UI + run: | + "${GITHUB_WORKSPACE}/portal-ui/tests/scripts/operator.sh" + + - name: Run TestCafe Tests + uses: DevExpress/testcafe-action@latest + with: + args: '"chrome:headless" portal-ui/tests/operator/tenant/test-4 --skip-js-errors -c 3' compile-job: name: Compiles on Go ${{ matrix.go-version }} and ${{ matrix.os }} diff --git a/portal-ui/tests/operator/login.ts b/portal-ui/tests/operator/login/login.ts similarity index 85% rename from portal-ui/tests/operator/login.ts rename to portal-ui/tests/operator/login/login.ts index b4805f978..570ddfcb7 100644 --- a/portal-ui/tests/operator/login.ts +++ b/portal-ui/tests/operator/login/login.ts @@ -14,9 +14,9 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -import * as roles from "../utils/roles"; -import * as elements from "../utils/elements"; -import { diagnosticsElement, supportElement } from "../utils/elements-menu"; +import * as roles from "../../utils/roles"; +import * as elements from "../../utils/elements"; +import { diagnosticsElement, supportElement } from "../../utils/elements-menu"; fixture("For user with default permissions").page("http://localhost:9090"); diff --git a/portal-ui/tests/operator/tenants.ts b/portal-ui/tests/operator/tenant/test-1/tenant-test-1.ts similarity index 95% rename from portal-ui/tests/operator/tenants.ts rename to portal-ui/tests/operator/tenant/test-1/tenant-test-1.ts index 23523827e..821e1f697 100644 --- a/portal-ui/tests/operator/tenants.ts +++ b/portal-ui/tests/operator/tenant/test-1/tenant-test-1.ts @@ -28,10 +28,11 @@ import { goToMonitoringSection, goToLoggingSection, goToLoggingDBSection, -} from "./utils"; +} from "../../utils"; fixture("For user with default permissions").page("http://localhost:9090"); +// Test 1 test("Create Tenant and List Tenants", async (t) => { const tenantName = `tenant-${Math.floor(Math.random() * 10000)}`; await loginToOperator(); @@ -39,6 +40,7 @@ test("Create Tenant and List Tenants", async (t) => { await deleteTenant(tenantName); }); +// Test 2 test("Create Tenant Without Audit Log", async (t) => { const tenantName = `tenant-${Math.floor(Math.random() * 10000)}`; await loginToOperator(); @@ -46,6 +48,7 @@ test("Create Tenant Without Audit Log", async (t) => { await deleteTenant(tenantName); }); +// Test 3 test("Test describe section for PODs in new tenant", async (t) => { const tenantName = "storage-lite"; await loginToOperator(); @@ -76,6 +79,7 @@ const checkPodDescribeHasSections = async () => { .ok(); }; +// Test 4 test("Test describe section for PVCs in new tenant", async (t) => { const tenantName = `storage-lite`; await loginToOperator(); @@ -487,27 +491,9 @@ const checkLoggingDBFieldsAcceptValues = async (tenantName: string) => { .ok(); }; +// Test 5 test("Test Prometheus monitoring can be disabled and enabled", async (t) => { const tenantName = `storage-lite`; await loginToOperator(); await checkMonitoringToggle(tenantName); }); - -test("Test Prometheus config fields can be edited and submitted", async (t) => { - const tenantName = `storage-lite`; - await loginToOperator(); - await checkMonitoringFieldsAcceptValues(tenantName); -}); - -test("Test Audit Logging can be disabled and enabled", async (t) => { - const tenantName = `storage-lite`; - await loginToOperator(); - await checkLoggingToggle(tenantName); -}); - -test("Test Audit Log config fields can be edited and submitted", async (t) => { - const tenantName = `storage-lite`; - await loginToOperator(); - await checkLoggingFieldsAcceptValues(tenantName); - await checkLoggingDBFieldsAcceptValues(tenantName); -}); diff --git a/portal-ui/tests/operator/tenant/test-2/tenant-test-2.ts b/portal-ui/tests/operator/tenant/test-2/tenant-test-2.ts new file mode 100644 index 000000000..bee3356c1 --- /dev/null +++ b/portal-ui/tests/operator/tenant/test-2/tenant-test-2.ts @@ -0,0 +1,469 @@ +// This file is part of MinIO Console Server +// Copyright (c) 2022 MinIO, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +import { t, Selector } from "testcafe"; +import { + loginToOperator, + createTenant, + createTenantWithoutAuditLog, + deleteTenant, + redirectToTenantsList, + goToPodInTenant, + goToPodSection, + goToPvcInTenant, + goToPvcSection, + goToMonitoringSection, + goToLoggingSection, + goToLoggingDBSection, +} from "../../utils"; + +fixture("For user with default permissions").page("http://localhost:9090"); + +const testPODDescribe = async (tenantName: string) => { + await goToPodInTenant(tenantName); + await goToPodSection(1); + await checkPodDescribeHasSections(); +}; + +const checkPodDescribeHasSections = async () => { + await t + .expect(Selector("#pod-describe-summary").exists) + .ok() + .expect(Selector("#pod-describe-annotations").exists) + .ok() + .expect(Selector("#pod-describe-labels").exists) + .ok() + .expect(Selector("#pod-describe-conditions").exists) + .ok() + .expect(Selector("#pod-describe-tolerations").exists) + .ok() + .expect(Selector("#pod-describe-volumes").exists) + .ok() + .expect(Selector("#pod-describe-containers").exists) + .ok(); +}; + +const testPvcDescribe = async (tenantName: string) => { + await goToPvcInTenant(tenantName); + await goToPvcSection(1); + await checkPvcDescribeHasSections(); +}; + +const checkPvcDescribeHasSections = async () => { + await t + .expect(Selector("#pvc-describe-summary").exists) + .ok() + .expect(Selector("#pvc-describe-annotations").exists) + .ok() + .expect(Selector("#pvc-describe-labels").exists) + .ok(); +}; + +export const checkMonitoringToggle = async (tenantName: string) => { + await goToMonitoringSection(tenantName); + await t + .click("#tenant-monitoring") + .click("#confirm-ok") + .wait(1000) + .expect(Selector("#image").exists) + .notOk() + .click("#yaml_button") + .expect(Selector("#code_wrapper").exists) + .ok(); + await t + .expect( + (await Selector("#code_wrapper").textContent).includes("prometheus:") + ) + .notOk(); + await t + .click(Selector(`a[href$="/monitoring"]`)) + .click("#tenant-monitoring") + .click("#confirm-ok") + .wait(5000) + .expect(Selector("#prometheus_image").exists) + .ok() + .click("#yaml_button") + .expect(Selector("#code_wrapper").exists) + .ok(); + await t + .expect( + (await Selector("#code_wrapper").textContent).includes("prometheus:") + ) + .ok(); +}; +export const checkMonitoringFieldsAcceptValues = async (tenantName: string) => { + await goToMonitoringSection(tenantName); + await t + .typeText("#prometheus_image", "quay.io/prometheus/prometheus:latest", { + replace: true, + }) + .typeText("#sidecarImage", "library/alpine:latest", { replace: true }) + .typeText("#initImage", "library/busybox:1.33.1", { replace: true }) + .typeText("#diskCapacityGB", "1", { replace: true }) + .typeText("#cpuRequest", "1", { replace: true }) + .typeText("#memRequest", "1", { replace: true }) + .typeText("#serviceAccountName", "monitoringTestServiceAccountName", { + replace: true, + }) + .typeText("#storageClassName", "monitoringTestStorageClassName", { + replace: true, + }) + .typeText("#securityContext_runAsUser", "1212", { replace: true }) + .typeText("#securityContext_runAsGroup", "3434", { replace: true }) + .typeText("#securityContext_fsGroup", "5656", { replace: true }) + .expect(Selector("#securityContext_runAsNonRoot").checked) + .ok() + .click("#securityContext_runAsNonRoot") + .expect(Selector("#securityContext_runAsNonRoot").checked) + .notOk() + .typeText("#key-Labels-0", "monitoringLabelKey0Test", { replace: true }) + .typeText("#val-Labels-0", "monitoringLabelVal0Test", { replace: true }) + .click("#add-Labels-0") + .typeText("#key-Annotations-0", "monitoringAnnotationsKey0Test", { + replace: true, + }) + .typeText("#val-Annotations-0", "monitoringAnnotationsVal0Test", { + replace: true, + }) + .click("#add-Annotations-0") + .typeText("#key-NodeSelector-0", "monitoringNodeSelectorKey0Test", { + replace: true, + }) + .typeText("#val-NodeSelector-0", "monitoringNodeSelectorVal0Test", { + replace: true, + }) + .click("#add-NodeSelector-0") + .expect(Selector("#key-Labels-1").exists) + .ok() + .expect(Selector("#key-Annotations-1").exists) + .ok() + .expect(Selector("#key-NodeSelector-1").exists) + .ok() + .click("#submit_button") + .click("#yaml_button") + .expect(Selector("#code_wrapper").exists) + .ok(); + await t + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("image: quay.io/prometheus/prometheus:latest") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("initimage: library/busybox:1.33.1") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("diskCapacityGB: 1") + ) + .ok() + .expect((await Selector("#code_wrapper").textContent).includes('cpu: "1"')) + .ok() + .expect( + (await Selector("#code_wrapper").textContent).includes("memory: 1Gi") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("serviceAccountName: monitoringTestServiceAccountName") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("sidecarimage: library/alpine:latest") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("storageClassName: monitoringTestStorageClassName") + ) + .ok() + .expect( + (await Selector("#code_wrapper").textContent).includes("fsGroup: 5656") + ) + .ok() + .expect( + (await Selector("#code_wrapper").textContent).includes("runAsGroup: 3434") + ) + .ok() + .expect( + (await Selector("#code_wrapper").textContent).includes("runAsUser: 1212") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("monitoringAnnotationsKey0Test: monitoringAnnotationsVal0Test") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes( + "monitoringNodeSelectorKey0Test: monitoringNodeSelectorVal0Test" + ) + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("monitoringLabelKey0Test: monitoringLabelVal0Test") + ) + .ok(); +}; + +const checkLoggingToggle = async (tenantName: string) => { + await goToLoggingSection(tenantName); + await t + .click("#tenant_logging") + .click("#confirm-ok") + .wait(3000) + .expect(Selector("#image").exists) + .notOk() + .click("#yaml_button") + .expect(Selector("#code_wrapper").exists) + .ok(); + await t + .expect((await Selector("#code_wrapper").textContent).includes("log:")) + .notOk(); + await t + .click(Selector(`a[href$="/logging"]`)) + .click("#tenant_logging") + .click("#confirm-ok") + .wait(3000) + .expect(Selector("#image").exists) + .ok() + .click("#yaml_button") + .expect(Selector("#code_wrapper").exists) + .ok(); + await t + .expect((await Selector("#code_wrapper").textContent).includes("log:")) + .ok(); +}; + +const checkLoggingFieldsAcceptValues = async (tenantName: string) => { + await goToLoggingSection(tenantName); + await t + .wait(3000) + .typeText("#image", "minio/operator:v4.4.22", { replace: true }) + .typeText("#diskCapacityGB", "3", { replace: true }) + .typeText("#cpuRequest", "3", { replace: true }) + .typeText("#memRequest", "3", { replace: true }) + .typeText("#serviceAccountName", "loggingTestServiceAccountName", { + replace: true, + }) + .typeText("#securityContext_runAsUser", "1111", { replace: true }) + .typeText("#securityContext_runAsGroup", "2222", { replace: true }) + .typeText("#securityContext_fsGroup", "3333", { replace: true }) + .expect(Selector("#securityContext_runAsNonRoot").checked) + .notOk() + .click("#securityContext_runAsNonRoot") + .expect(Selector("#securityContext_runAsNonRoot").checked) + .ok() + .typeText("#key-Labels-0", "loggingLabelKey0Test", { replace: true }) + .typeText("#val-Labels-0", "loggingLabelVal0Test", { replace: true }) + .click("#add-Labels-0") + .typeText("#key-Annotations-0", "loggingAnnotationsKey0Test", { + replace: true, + }) + .typeText("#val-Annotations-0", "loggingAnnotationsVal0Test", { + replace: true, + }) + .click("#add-Annotations-0") + .typeText("#key-NodeSelector-0", "loggingNodeSelectorKey0Test", { + replace: true, + }) + .typeText("#val-NodeSelector-0", "loggingNodeSelectorVal0Test", { + replace: true, + }) + .click("#add-NodeSelector-0") + .expect(Selector("#key-Labels-1").exists) + .ok() + .expect(Selector("#key-Annotations-1").exists) + .ok() + .expect(Selector("#key-NodeSelector-1").exists) + .ok() + .click("#submit_button") + .click("#yaml_button") + .expect(Selector("#code_wrapper").exists) + .ok(); + await t + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("image: minio/operator:v4.4.22") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("diskCapacityGB: 3") + ) + .ok() + .expect((await Selector("#code_wrapper").textContent).includes('cpu: "3"')) + .ok() + .expect( + (await Selector("#code_wrapper").textContent).includes('memory: "3"') + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("serviceAccountName: loggingTestServiceAccountName") + ) + .ok() + .expect( + (await Selector("#code_wrapper").textContent).includes("fsGroup: 3333") + ) + .ok() + .expect( + (await Selector("#code_wrapper").textContent).includes("runAsGroup: 2222") + ) + .ok() + .expect( + (await Selector("#code_wrapper").textContent).includes("runAsUser: 1111") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("AnnotationsKey0Test: loggingAnnotationsVal0Test") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("NodeSelectorKey0Test: loggingNodeSelectorVal0Test") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("loggingLabelKey0Test: loggingLabelVal0Test") + ) + .ok(); +}; + +const checkLoggingDBFieldsAcceptValues = async (tenantName: string) => { + await goToLoggingDBSection(tenantName); + await t + .typeText("#dbImage", "library/postgres:13", { replace: true }) + .typeText("#dbInitImage", "library/busybox:1.33.1", { replace: true }) + .typeText("#dbCPURequest", "4", { replace: true }) + .typeText("#dbMemRequest", "4", { replace: true }) + .typeText("#securityContext_runAsUser", "4444", { replace: true }) + .typeText("#securityContext_runAsGroup", "5555", { replace: true }) + .typeText("#securityContext_fsGroup", "6666", { replace: true }) + .expect(Selector("#securityContext_runAsNonRoot").checked) + .notOk() + .click("#securityContext_runAsNonRoot") + .expect(Selector("#securityContext_runAsNonRoot").checked) + .ok() + .typeText("#key-dbLabels-0", "loggingdbLabelKey0Test", { replace: true }) + .typeText("#val-dbLabels-0", "loggingdbLabelVal0Test", { replace: true }) + .click("#add-dbLabels-0") + .typeText("#key-dbAnnotations-0", "loggingdbAnnotationsKey0Test", { + replace: true, + }) + .typeText("#val-dbAnnotations-0", "loggingdbAnnotationsVal0Test", { + replace: true, + }) + .click("#add-dbAnnotations-0") + .typeText("#key-DBNodeSelector-0", "loggingdbNodeSelectorKey0Test", { + replace: true, + }) + .typeText("#val-DBNodeSelector-0", "loggingdbNodeSelectorVal0Test", { + replace: true, + }) + .click("#add-DBNodeSelector-0") + .expect(Selector("#key-dbLabels-1").exists) + .ok() + .expect(Selector("#key-dbAnnotations-1").exists) + .ok() + .expect(Selector("#key-DBNodeSelector-1").exists) + .ok() + .click("#remove-dbLabels-1") + .click("#remove-dbAnnotations-1") + .click("#remove-DBNodeSelector-1") + .expect(Selector("#key-dbLabels-1").exists) + .notOk() + .expect(Selector("#key-dbAnnotations-1").exists) + .notOk() + .expect(Selector("#key-DBNodeSelector-1").exists) + .notOk() + .click("#submit_button") + .click("#yaml_button") + .expect(Selector("#code_wrapper").exists) + .ok(); + await t + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("image: library/postgres:13") + ) + .ok() + .expect((await Selector("#code_wrapper").textContent).includes('cpu: "4"')) + .ok() + .expect( + (await Selector("#code_wrapper").textContent).includes('memory: "4"') + ) + .ok() + .expect( + (await Selector("#code_wrapper").textContent).includes("fsGroup: 6666") + ) + .ok() + .expect( + (await Selector("#code_wrapper").textContent).includes("runAsGroup: 5555") + ) + .ok() + .expect( + (await Selector("#code_wrapper").textContent).includes("runAsUser: 4444") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("loggingdbAnnotationsKey0Test: loggingdbAnnotationsVal0Test") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("loggingdbNodeSelectorKey0Test: loggingdbNodeSelectorVal0Test") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("loggingdbLabelKey0Test: loggingdbLabelVal0Test") + ) + .ok(); +}; + +// Test 1 +test("Test Prometheus config fields can be edited and submitted", async (t) => { + const tenantName = `storage-lite`; + await loginToOperator(); + await checkMonitoringFieldsAcceptValues(tenantName); +}); diff --git a/portal-ui/tests/operator/tenant/test-3/tenant-test-3.ts b/portal-ui/tests/operator/tenant/test-3/tenant-test-3.ts new file mode 100644 index 000000000..1648aca63 --- /dev/null +++ b/portal-ui/tests/operator/tenant/test-3/tenant-test-3.ts @@ -0,0 +1,473 @@ +// This file is part of MinIO Console Server +// Copyright (c) 2022 MinIO, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +import { t, Selector } from "testcafe"; +import { + loginToOperator, + createTenant, + createTenantWithoutAuditLog, + deleteTenant, + redirectToTenantsList, + goToPodInTenant, + goToPodSection, + goToPvcInTenant, + goToPvcSection, + goToMonitoringSection, + goToLoggingSection, + goToLoggingDBSection, +} from "../../utils"; + +fixture("For user with default permissions").page("http://localhost:9090"); + +const testPODDescribe = async (tenantName: string) => { + await goToPodInTenant(tenantName); + await goToPodSection(1); + await checkPodDescribeHasSections(); +}; + +const checkPodDescribeHasSections = async () => { + await t + .expect(Selector("#pod-describe-summary").exists) + .ok() + .expect(Selector("#pod-describe-annotations").exists) + .ok() + .expect(Selector("#pod-describe-labels").exists) + .ok() + .expect(Selector("#pod-describe-conditions").exists) + .ok() + .expect(Selector("#pod-describe-tolerations").exists) + .ok() + .expect(Selector("#pod-describe-volumes").exists) + .ok() + .expect(Selector("#pod-describe-containers").exists) + .ok(); +}; + +const testPvcDescribe = async (tenantName: string) => { + await goToPvcInTenant(tenantName); + await goToPvcSection(1); + await checkPvcDescribeHasSections(); +}; + +const checkPvcDescribeHasSections = async () => { + await t + .expect(Selector("#pvc-describe-summary").exists) + .ok() + .expect(Selector("#pvc-describe-annotations").exists) + .ok() + .expect(Selector("#pvc-describe-labels").exists) + .ok(); +}; + +export const checkMonitoringToggle = async (tenantName: string) => { + await goToMonitoringSection(tenantName); + await t + .click("#tenant-monitoring") + .click("#confirm-ok") + .wait(1000) + .expect(Selector("#image").exists) + .notOk() + .click("#yaml_button") + .expect(Selector("#code_wrapper").exists) + .ok(); + await t + .expect( + (await Selector("#code_wrapper").textContent).includes("prometheus:") + ) + .notOk(); + await t + .click(Selector(`a[href$="/monitoring"]`)) + .click("#tenant-monitoring") + .click("#confirm-ok") + .wait(5000) + .expect(Selector("#prometheus_image").exists) + .ok() + .click("#yaml_button") + .expect(Selector("#code_wrapper").exists) + .ok(); + await t + .expect( + (await Selector("#code_wrapper").textContent).includes("prometheus:") + ) + .ok(); +}; +export const checkMonitoringFieldsAcceptValues = async (tenantName: string) => { + await goToMonitoringSection(tenantName); + await t + .typeText("#prometheus_image", "quay.io/prometheus/prometheus:latest", { + replace: true, + }) + .typeText("#sidecarImage", "library/alpine:latest", { replace: true }) + .typeText("#initImage", "library/busybox:1.33.1", { replace: true }) + .typeText("#diskCapacityGB", "1", { replace: true }) + .typeText("#cpuRequest", "1", { replace: true }) + .typeText("#memRequest", "1", { replace: true }) + .typeText("#serviceAccountName", "monitoringTestServiceAccountName", { + replace: true, + }) + .typeText("#storageClassName", "monitoringTestStorageClassName", { + replace: true, + }) + .typeText("#securityContext_runAsUser", "1212", { replace: true }) + .typeText("#securityContext_runAsGroup", "3434", { replace: true }) + .typeText("#securityContext_fsGroup", "5656", { replace: true }) + .expect(Selector("#securityContext_runAsNonRoot").checked) + .ok() + .click("#securityContext_runAsNonRoot") + .expect(Selector("#securityContext_runAsNonRoot").checked) + .notOk() + .typeText("#key-Labels-0", "monitoringLabelKey0Test", { replace: true }) + .typeText("#val-Labels-0", "monitoringLabelVal0Test", { replace: true }) + .click("#add-Labels-0") + .typeText("#key-Annotations-0", "monitoringAnnotationsKey0Test", { + replace: true, + }) + .typeText("#val-Annotations-0", "monitoringAnnotationsVal0Test", { + replace: true, + }) + .click("#add-Annotations-0") + .typeText("#key-NodeSelector-0", "monitoringNodeSelectorKey0Test", { + replace: true, + }) + .typeText("#val-NodeSelector-0", "monitoringNodeSelectorVal0Test", { + replace: true, + }) + .click("#add-NodeSelector-0") + .expect(Selector("#key-Labels-1").exists) + .ok() + .expect(Selector("#key-Annotations-1").exists) + .ok() + .expect(Selector("#key-NodeSelector-1").exists) + .ok() + .click("#submit_button") + .click("#yaml_button") + .expect(Selector("#code_wrapper").exists) + .ok(); + await t + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("image: quay.io/prometheus/prometheus:latest") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("initimage: library/busybox:1.33.1") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("diskCapacityGB: 1") + ) + .ok() + .expect((await Selector("#code_wrapper").textContent).includes('cpu: "1"')) + .ok() + .expect( + (await Selector("#code_wrapper").textContent).includes("memory: 1Gi") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("serviceAccountName: monitoringTestServiceAccountName") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("sidecarimage: library/alpine:latest") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("storageClassName: monitoringTestStorageClassName") + ) + .ok() + .expect( + (await Selector("#code_wrapper").textContent).includes("fsGroup: 5656") + ) + .ok() + .expect( + (await Selector("#code_wrapper").textContent).includes("runAsGroup: 3434") + ) + .ok() + .expect( + (await Selector("#code_wrapper").textContent).includes("runAsUser: 1212") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("monitoringAnnotationsKey0Test: monitoringAnnotationsVal0Test") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes( + "monitoringNodeSelectorKey0Test: monitoringNodeSelectorVal0Test" + ) + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("monitoringLabelKey0Test: monitoringLabelVal0Test") + ) + .ok(); +}; + +const checkLoggingToggle = async (tenantName: string) => { + await goToLoggingSection(tenantName); + await t + .click("#tenant_logging") + .click("#confirm-ok") + .wait(3000) + .expect(Selector("#image").exists) + .notOk() + .click("#yaml_button") + .expect(Selector("#code_wrapper").exists) + .ok(); + await t + .expect((await Selector("#code_wrapper").textContent).includes("log:")) + .notOk(); + await t + .click(Selector(`a[href$="/logging"]`)) + .click("#tenant_logging") + .click("#confirm-ok") + .wait(3000) + .expect(Selector("#image").exists) + .ok() + .click("#yaml_button") + .expect(Selector("#code_wrapper").exists) + .ok(); + await t + .expect((await Selector("#code_wrapper").textContent).includes("log:")) + .ok(); +}; + +const checkLoggingFieldsAcceptValues = async (tenantName: string) => { + await goToLoggingSection(tenantName); + await t + .wait(3000) + .typeText("#image", "minio/operator:v4.4.22", { replace: true }) + .typeText("#diskCapacityGB", "3", { replace: true }) + .typeText("#cpuRequest", "3", { replace: true }) + .typeText("#memRequest", "3", { replace: true }) + .typeText("#serviceAccountName", "loggingTestServiceAccountName", { + replace: true, + }) + .typeText("#securityContext_runAsUser", "1111", { replace: true }) + .typeText("#securityContext_runAsGroup", "2222", { replace: true }) + .typeText("#securityContext_fsGroup", "3333", { replace: true }) + .expect(Selector("#securityContext_runAsNonRoot").exists) + .ok(); + await t.wait(3000); + await t + .expect(Selector("#securityContext_runAsNonRoot").checked) + .notOk() + .click("#securityContext_runAsNonRoot") + .expect(Selector("#securityContext_runAsNonRoot").checked) + .ok() + .typeText("#key-Labels-0", "loggingLabelKey0Test", { replace: true }) + .typeText("#val-Labels-0", "loggingLabelVal0Test", { replace: true }) + .click("#add-Labels-0") + .typeText("#key-Annotations-0", "loggingAnnotationsKey0Test", { + replace: true, + }) + .typeText("#val-Annotations-0", "loggingAnnotationsVal0Test", { + replace: true, + }) + .click("#add-Annotations-0") + .typeText("#key-NodeSelector-0", "loggingNodeSelectorKey0Test", { + replace: true, + }) + .typeText("#val-NodeSelector-0", "loggingNodeSelectorVal0Test", { + replace: true, + }) + .click("#add-NodeSelector-0") + .expect(Selector("#key-Labels-1").exists) + .ok() + .expect(Selector("#key-Annotations-1").exists) + .ok() + .expect(Selector("#key-NodeSelector-1").exists) + .ok() + .click("#submit_button") + .click("#yaml_button") + .expect(Selector("#code_wrapper").exists) + .ok(); + await t + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("image: minio/operator:v4.4.22") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("diskCapacityGB: 3") + ) + .ok() + .expect((await Selector("#code_wrapper").textContent).includes('cpu: "3"')) + .ok() + .expect( + (await Selector("#code_wrapper").textContent).includes('memory: "3"') + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("serviceAccountName: loggingTestServiceAccountName") + ) + .ok() + .expect( + (await Selector("#code_wrapper").textContent).includes("fsGroup: 3333") + ) + .ok() + .expect( + (await Selector("#code_wrapper").textContent).includes("runAsGroup: 2222") + ) + .ok() + .expect( + (await Selector("#code_wrapper").textContent).includes("runAsUser: 1111") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("AnnotationsKey0Test: loggingAnnotationsVal0Test") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("NodeSelectorKey0Test: loggingNodeSelectorVal0Test") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("loggingLabelKey0Test: loggingLabelVal0Test") + ) + .ok(); +}; + +const checkLoggingDBFieldsAcceptValues = async (tenantName: string) => { + await goToLoggingDBSection(tenantName); + await t + .typeText("#dbImage", "library/postgres:13", { replace: true }) + .typeText("#dbInitImage", "library/busybox:1.33.1", { replace: true }) + .typeText("#dbCPURequest", "4", { replace: true }) + .typeText("#dbMemRequest", "4", { replace: true }) + .typeText("#securityContext_runAsUser", "4444", { replace: true }) + .typeText("#securityContext_runAsGroup", "5555", { replace: true }) + .typeText("#securityContext_fsGroup", "6666", { replace: true }) + .expect(Selector("#securityContext_runAsNonRoot").checked) + .notOk() + .click("#securityContext_runAsNonRoot") + .expect(Selector("#securityContext_runAsNonRoot").checked) + .ok() + .typeText("#key-dbLabels-0", "loggingdbLabelKey0Test", { replace: true }) + .typeText("#val-dbLabels-0", "loggingdbLabelVal0Test", { replace: true }) + .click("#add-dbLabels-0") + .typeText("#key-dbAnnotations-0", "loggingdbAnnotationsKey0Test", { + replace: true, + }) + .typeText("#val-dbAnnotations-0", "loggingdbAnnotationsVal0Test", { + replace: true, + }) + .click("#add-dbAnnotations-0") + .typeText("#key-DBNodeSelector-0", "loggingdbNodeSelectorKey0Test", { + replace: true, + }) + .typeText("#val-DBNodeSelector-0", "loggingdbNodeSelectorVal0Test", { + replace: true, + }) + .click("#add-DBNodeSelector-0") + .expect(Selector("#key-dbLabels-1").exists) + .ok() + .expect(Selector("#key-dbAnnotations-1").exists) + .ok() + .expect(Selector("#key-DBNodeSelector-1").exists) + .ok() + .click("#remove-dbLabels-1") + .click("#remove-dbAnnotations-1") + .click("#remove-DBNodeSelector-1") + .expect(Selector("#key-dbLabels-1").exists) + .notOk() + .expect(Selector("#key-dbAnnotations-1").exists) + .notOk() + .expect(Selector("#key-DBNodeSelector-1").exists) + .notOk() + .click("#submit_button") + .click("#yaml_button") + .expect(Selector("#code_wrapper").exists) + .ok(); + await t + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("image: library/postgres:13") + ) + .ok() + .expect((await Selector("#code_wrapper").textContent).includes('cpu: "4"')) + .ok() + .expect( + (await Selector("#code_wrapper").textContent).includes('memory: "4"') + ) + .ok() + .expect( + (await Selector("#code_wrapper").textContent).includes("fsGroup: 6666") + ) + .ok() + .expect( + (await Selector("#code_wrapper").textContent).includes("runAsGroup: 5555") + ) + .ok() + .expect( + (await Selector("#code_wrapper").textContent).includes("runAsUser: 4444") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("loggingdbAnnotationsKey0Test: loggingdbAnnotationsVal0Test") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("loggingdbNodeSelectorKey0Test: loggingdbNodeSelectorVal0Test") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("loggingdbLabelKey0Test: loggingdbLabelVal0Test") + ) + .ok(); +}; + +// Test 1 +test("Test Audit Logging can be disabled and enabled", async (t) => { + const tenantName = `storage-lite`; + await loginToOperator(); + await checkLoggingToggle(tenantName); +}); diff --git a/portal-ui/tests/operator/tenant/test-4/tenant-test-4.ts b/portal-ui/tests/operator/tenant/test-4/tenant-test-4.ts new file mode 100644 index 000000000..9a83ff13e --- /dev/null +++ b/portal-ui/tests/operator/tenant/test-4/tenant-test-4.ts @@ -0,0 +1,474 @@ +// This file is part of MinIO Console Server +// Copyright (c) 2022 MinIO, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +import { t, Selector } from "testcafe"; +import { + loginToOperator, + createTenant, + createTenantWithoutAuditLog, + deleteTenant, + redirectToTenantsList, + goToPodInTenant, + goToPodSection, + goToPvcInTenant, + goToPvcSection, + goToMonitoringSection, + goToLoggingSection, + goToLoggingDBSection, +} from "../../utils"; + +fixture("For user with default permissions").page("http://localhost:9090"); + +const testPODDescribe = async (tenantName: string) => { + await goToPodInTenant(tenantName); + await goToPodSection(1); + await checkPodDescribeHasSections(); +}; + +const checkPodDescribeHasSections = async () => { + await t + .expect(Selector("#pod-describe-summary").exists) + .ok() + .expect(Selector("#pod-describe-annotations").exists) + .ok() + .expect(Selector("#pod-describe-labels").exists) + .ok() + .expect(Selector("#pod-describe-conditions").exists) + .ok() + .expect(Selector("#pod-describe-tolerations").exists) + .ok() + .expect(Selector("#pod-describe-volumes").exists) + .ok() + .expect(Selector("#pod-describe-containers").exists) + .ok(); +}; + +const testPvcDescribe = async (tenantName: string) => { + await goToPvcInTenant(tenantName); + await goToPvcSection(1); + await checkPvcDescribeHasSections(); +}; + +const checkPvcDescribeHasSections = async () => { + await t + .expect(Selector("#pvc-describe-summary").exists) + .ok() + .expect(Selector("#pvc-describe-annotations").exists) + .ok() + .expect(Selector("#pvc-describe-labels").exists) + .ok(); +}; + +export const checkMonitoringToggle = async (tenantName: string) => { + await goToMonitoringSection(tenantName); + await t + .click("#tenant-monitoring") + .click("#confirm-ok") + .wait(1000) + .expect(Selector("#image").exists) + .notOk() + .click("#yaml_button") + .expect(Selector("#code_wrapper").exists) + .ok(); + await t + .expect( + (await Selector("#code_wrapper").textContent).includes("prometheus:") + ) + .notOk(); + await t + .click(Selector(`a[href$="/monitoring"]`)) + .click("#tenant-monitoring") + .click("#confirm-ok") + .wait(5000) + .expect(Selector("#prometheus_image").exists) + .ok() + .click("#yaml_button") + .expect(Selector("#code_wrapper").exists) + .ok(); + await t + .expect( + (await Selector("#code_wrapper").textContent).includes("prometheus:") + ) + .ok(); +}; +export const checkMonitoringFieldsAcceptValues = async (tenantName: string) => { + await goToMonitoringSection(tenantName); + await t + .typeText("#prometheus_image", "quay.io/prometheus/prometheus:latest", { + replace: true, + }) + .typeText("#sidecarImage", "library/alpine:latest", { replace: true }) + .typeText("#initImage", "library/busybox:1.33.1", { replace: true }) + .typeText("#diskCapacityGB", "1", { replace: true }) + .typeText("#cpuRequest", "1", { replace: true }) + .typeText("#memRequest", "1", { replace: true }) + .typeText("#serviceAccountName", "monitoringTestServiceAccountName", { + replace: true, + }) + .typeText("#storageClassName", "monitoringTestStorageClassName", { + replace: true, + }) + .typeText("#securityContext_runAsUser", "1212", { replace: true }) + .typeText("#securityContext_runAsGroup", "3434", { replace: true }) + .typeText("#securityContext_fsGroup", "5656", { replace: true }) + .expect(Selector("#securityContext_runAsNonRoot").checked) + .ok() + .click("#securityContext_runAsNonRoot") + .expect(Selector("#securityContext_runAsNonRoot").checked) + .notOk() + .typeText("#key-Labels-0", "monitoringLabelKey0Test", { replace: true }) + .typeText("#val-Labels-0", "monitoringLabelVal0Test", { replace: true }) + .click("#add-Labels-0") + .typeText("#key-Annotations-0", "monitoringAnnotationsKey0Test", { + replace: true, + }) + .typeText("#val-Annotations-0", "monitoringAnnotationsVal0Test", { + replace: true, + }) + .click("#add-Annotations-0") + .typeText("#key-NodeSelector-0", "monitoringNodeSelectorKey0Test", { + replace: true, + }) + .typeText("#val-NodeSelector-0", "monitoringNodeSelectorVal0Test", { + replace: true, + }) + .click("#add-NodeSelector-0") + .expect(Selector("#key-Labels-1").exists) + .ok() + .expect(Selector("#key-Annotations-1").exists) + .ok() + .expect(Selector("#key-NodeSelector-1").exists) + .ok() + .click("#submit_button") + .click("#yaml_button") + .expect(Selector("#code_wrapper").exists) + .ok(); + await t + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("image: quay.io/prometheus/prometheus:latest") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("initimage: library/busybox:1.33.1") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("diskCapacityGB: 1") + ) + .ok() + .expect((await Selector("#code_wrapper").textContent).includes('cpu: "1"')) + .ok() + .expect( + (await Selector("#code_wrapper").textContent).includes("memory: 1Gi") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("serviceAccountName: monitoringTestServiceAccountName") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("sidecarimage: library/alpine:latest") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("storageClassName: monitoringTestStorageClassName") + ) + .ok() + .expect( + (await Selector("#code_wrapper").textContent).includes("fsGroup: 5656") + ) + .ok() + .expect( + (await Selector("#code_wrapper").textContent).includes("runAsGroup: 3434") + ) + .ok() + .expect( + (await Selector("#code_wrapper").textContent).includes("runAsUser: 1212") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("monitoringAnnotationsKey0Test: monitoringAnnotationsVal0Test") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes( + "monitoringNodeSelectorKey0Test: monitoringNodeSelectorVal0Test" + ) + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("monitoringLabelKey0Test: monitoringLabelVal0Test") + ) + .ok(); +}; + +const checkLoggingToggle = async (tenantName: string) => { + await goToLoggingSection(tenantName); + await t + .click("#tenant_logging") + .click("#confirm-ok") + .wait(3000) + .expect(Selector("#image").exists) + .notOk() + .click("#yaml_button") + .expect(Selector("#code_wrapper").exists) + .ok(); + await t + .expect((await Selector("#code_wrapper").textContent).includes("log:")) + .notOk(); + await t + .click(Selector(`a[href$="/logging"]`)) + .click("#tenant_logging") + .click("#confirm-ok") + .wait(3000) + .expect(Selector("#image").exists) + .ok() + .click("#yaml_button") + .expect(Selector("#code_wrapper").exists) + .ok(); + await t + .expect((await Selector("#code_wrapper").textContent).includes("log:")) + .ok(); +}; + +const checkLoggingFieldsAcceptValues = async (tenantName: string) => { + await goToLoggingSection(tenantName); + await t + .wait(3000) + .typeText("#image", "minio/operator:v4.4.22", { replace: true }) + .typeText("#diskCapacityGB", "3", { replace: true }) + .typeText("#cpuRequest", "3", { replace: true }) + .typeText("#memRequest", "3", { replace: true }) + .typeText("#serviceAccountName", "loggingTestServiceAccountName", { + replace: true, + }) + .typeText("#securityContext_runAsUser", "1111", { replace: true }) + .typeText("#securityContext_runAsGroup", "2222", { replace: true }) + .typeText("#securityContext_fsGroup", "3333", { replace: true }) + .expect(Selector("#securityContext_runAsNonRoot").exists) + .ok(); + await t.wait(3000); + await t + .expect(Selector("#securityContext_runAsNonRoot").checked) + .ok() + .click("#securityContext_runAsNonRoot") + .expect(Selector("#securityContext_runAsNonRoot").checked) + .notOk() + .typeText("#key-Labels-0", "loggingLabelKey0Test", { replace: true }) + .typeText("#val-Labels-0", "loggingLabelVal0Test", { replace: true }) + .click("#add-Labels-0") + .typeText("#key-Annotations-0", "loggingAnnotationsKey0Test", { + replace: true, + }) + .typeText("#val-Annotations-0", "loggingAnnotationsVal0Test", { + replace: true, + }) + .click("#add-Annotations-0") + .typeText("#key-NodeSelector-0", "loggingNodeSelectorKey0Test", { + replace: true, + }) + .typeText("#val-NodeSelector-0", "loggingNodeSelectorVal0Test", { + replace: true, + }) + .click("#add-NodeSelector-0") + .expect(Selector("#key-Labels-1").exists) + .ok() + .expect(Selector("#key-Annotations-1").exists) + .ok() + .expect(Selector("#key-NodeSelector-1").exists) + .ok() + .click("#submit_button") + .click("#yaml_button") + .expect(Selector("#code_wrapper").exists) + .ok(); + await t + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("image: minio/operator:v4.4.22") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("diskCapacityGB: 3") + ) + .ok() + .expect((await Selector("#code_wrapper").textContent).includes('cpu: "3"')) + .ok() + .expect( + (await Selector("#code_wrapper").textContent).includes('memory: "3"') + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("serviceAccountName: loggingTestServiceAccountName") + ) + .ok() + .expect( + (await Selector("#code_wrapper").textContent).includes("fsGroup: 3333") + ) + .ok() + .expect( + (await Selector("#code_wrapper").textContent).includes("runAsGroup: 2222") + ) + .ok() + .expect( + (await Selector("#code_wrapper").textContent).includes("runAsUser: 1111") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("AnnotationsKey0Test: loggingAnnotationsVal0Test") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("NodeSelectorKey0Test: loggingNodeSelectorVal0Test") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("loggingLabelKey0Test: loggingLabelVal0Test") + ) + .ok(); +}; + +const checkLoggingDBFieldsAcceptValues = async (tenantName: string) => { + await goToLoggingDBSection(tenantName); + await t + .typeText("#dbImage", "library/postgres:13", { replace: true }) + .typeText("#dbInitImage", "library/busybox:1.33.1", { replace: true }) + .typeText("#dbCPURequest", "4", { replace: true }) + .typeText("#dbMemRequest", "4", { replace: true }) + .typeText("#securityContext_runAsUser", "4444", { replace: true }) + .typeText("#securityContext_runAsGroup", "5555", { replace: true }) + .typeText("#securityContext_fsGroup", "6666", { replace: true }) + .expect(Selector("#securityContext_runAsNonRoot").checked) + .ok() + .click("#securityContext_runAsNonRoot") + .expect(Selector("#securityContext_runAsNonRoot").checked) + .notOk() + .typeText("#key-dbLabels-0", "loggingdbLabelKey0Test", { replace: true }) + .typeText("#val-dbLabels-0", "loggingdbLabelVal0Test", { replace: true }) + .click("#add-dbLabels-0") + .typeText("#key-dbAnnotations-0", "loggingdbAnnotationsKey0Test", { + replace: true, + }) + .typeText("#val-dbAnnotations-0", "loggingdbAnnotationsVal0Test", { + replace: true, + }) + .click("#add-dbAnnotations-0") + .typeText("#key-DBNodeSelector-0", "loggingdbNodeSelectorKey0Test", { + replace: true, + }) + .typeText("#val-DBNodeSelector-0", "loggingdbNodeSelectorVal0Test", { + replace: true, + }) + .click("#add-DBNodeSelector-0") + .expect(Selector("#key-dbLabels-1").exists) + .ok() + .expect(Selector("#key-dbAnnotations-1").exists) + .ok() + .expect(Selector("#key-DBNodeSelector-1").exists) + .ok() + .click("#remove-dbLabels-1") + .click("#remove-dbAnnotations-1") + .click("#remove-DBNodeSelector-1") + .expect(Selector("#key-dbLabels-1").exists) + .notOk() + .expect(Selector("#key-dbAnnotations-1").exists) + .notOk() + .expect(Selector("#key-DBNodeSelector-1").exists) + .notOk() + .click("#submit_button") + .click("#yaml_button") + .expect(Selector("#code_wrapper").exists) + .ok(); + await t + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("image: library/postgres:13") + ) + .ok() + .expect((await Selector("#code_wrapper").textContent).includes('cpu: "4"')) + .ok() + .expect( + (await Selector("#code_wrapper").textContent).includes('memory: "4"') + ) + .ok() + .expect( + (await Selector("#code_wrapper").textContent).includes("fsGroup: 6666") + ) + .ok() + .expect( + (await Selector("#code_wrapper").textContent).includes("runAsGroup: 5555") + ) + .ok() + .expect( + (await Selector("#code_wrapper").textContent).includes("runAsUser: 4444") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("loggingdbAnnotationsKey0Test: loggingdbAnnotationsVal0Test") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("loggingdbNodeSelectorKey0Test: loggingdbNodeSelectorVal0Test") + ) + .ok() + .expect( + ( + await Selector("#code_wrapper").textContent + ).includes("loggingdbLabelKey0Test: loggingdbLabelVal0Test") + ) + .ok(); +}; + +// Test 1 +test("Test Audit Log config fields can be edited and submitted", async (t) => { + const tenantName = `storage-lite`; + await loginToOperator(); + await checkLoggingFieldsAcceptValues(tenantName); + await checkLoggingDBFieldsAcceptValues(tenantName); +});