From d4176e2ee74e19a02af0156f241c9f766ed6d096 Mon Sep 17 00:00:00 2001 From: Artem Rys Date: Thu, 14 Nov 2024 15:45:22 +0100 Subject: [PATCH 1/2] ci: split UI tests (#1460) **Issue number:** N/A ### PR Type **What kind of change does this PR introduce?** * [ ] Feature * [ ] Bug Fix * [ ] Refactoring (no functional or API changes) * [ ] Documentation Update * [x] Maintenance (dependency updates, CI, etc.) ## Summary ### Changes Splitting UI tests in GitHub Actions pipeline. According to the run from this PR - the whole pipeline time dropped 50%. I checked the total amount of test cases run and it is the same as in the previous approach. ### User experience N/A ## Checklist If an item doesn't apply to your changes, leave it unchecked. * [x] I have performed a self-review of this change according to the [development guidelines](https://splunk.github.io/addonfactory-ucc-generator/contributing/#development-guidelines) * [ ] Tests have been added/modified to cover the changes [(testing doc)](https://splunk.github.io/addonfactory-ucc-generator/contributing/#build-and-test) * [ ] Changes are documented * [x] PR title and description follows the [contributing principles](https://splunk.github.io/addonfactory-ucc-generator/contributing/#pull-requests) --- .github/workflows/build-test-release.yml | 27 +++++++++++++----------- poetry.lock | 16 +++++++++++++- pyproject.toml | 1 + 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/.github/workflows/build-test-release.yml b/.github/workflows/build-test-release.yml index 98f67b57e..495d32f30 100644 --- a/.github/workflows/build-test-release.yml +++ b/.github/workflows/build-test-release.yml @@ -227,7 +227,7 @@ jobs: path: Splunk_TA_UCCExample*.tar.gz test-ui: - name: test-ui Splunk ${{ matrix.splunk.version }} -m ${{ matrix.test-mark }} + name: test-ui Splunk ${{ matrix.splunk.version }} -group ${{ matrix.test-group }} runs-on: ubuntu-22.04 permissions: id-token: write @@ -243,14 +243,17 @@ jobs: fail-fast: false matrix: splunk: ${{ fromJson(needs.meta.outputs.matrix_supportedSplunk) }} - test-mark: - - "logging" - - "proxy" - - "account" - - "custom" - - "alert" - - "input" - - "configuration" + test-group: + - "1" + - "2" + - "3" + - "4" + - "5" + - "6" + - "7" + - "8" + - "9" + - "10" steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 @@ -272,16 +275,16 @@ jobs: ./scripts/run_splunk.sh ${{ matrix.splunk.version }} until curl -Lsk "https://localhost:8088/services/collector/health" &>/dev/null ; do echo -n "Waiting for HEC-" && sleep 5 ; done timeout-minutes: 5 - - run: poetry run pytest tests/ui -m "${{ matrix.test-mark }}" --headless --junitxml=test-results/junit.xml + - run: poetry run pytest tests/ui --test-group-count 10 --test-group ${{ matrix.test-group }} --test-group-random-seed 123456 --headless --junitxml=test-results/junit.xml - uses: actions/upload-artifact@v4 if: success() || failure() with: - name: test-results-ui-${{ matrix.splunk.version }}-${{ matrix.test-mark }} + name: test-results-ui-${{ matrix.splunk.version }}-${{ matrix.test-group }} path: test-results/* - uses: dorny/test-reporter@v1 if: success() || failure() with: - name: test-report-ui-${{ matrix.splunk.version }}-${{ matrix.test-mark }} + name: test-report-ui-${{ matrix.splunk.version }}-${{ matrix.test-group }} path: "test-results/*.xml" reporter: java-junit diff --git a/poetry.lock b/poetry.lock index 0aade8ad5..138e67e22 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1239,6 +1239,20 @@ importlib-metadata = {version = ">=1", markers = "python_version < \"3.8\""} packaging = ">=17.1" pytest = ">=5.3" +[[package]] +name = "pytest-split-tests" +version = "1.1.0" +description = "A Pytest plugin for running a subset of your tests by splitting them in to equally sized groups. Forked from Mark Adams' original project pytest-test-groups." +optional = false +python-versions = "*" +files = [ + {file = "pytest-split-tests-1.1.0.tar.gz", hash = "sha256:e55bbf127d94ff913a248f32e64f07cd3201e8a82397e8152694e4ffe456e21c"}, + {file = "pytest_split_tests-1.1.0-py2.py3-none-any.whl", hash = "sha256:21be7d6f95291002790fe24e28faa950059694e7abc430d4993d99a4c773bde4"}, +] + +[package.dependencies] +pytest = ">=2.5" + [[package]] name = "pytest-splunk-addon" version = "5.4.1" @@ -1768,4 +1782,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more [metadata] lock-version = "2.0" python-versions = ">=3.7,<3.13" -content-hash = "f0072f7b472f7556af341f351358bed09701afd1b0b014e296a4c5fec118c4c6" +content-hash = "0435209576291a24a097f17bcf32f89216d592fb01e88fe72c521cb7379ff474" diff --git a/pyproject.toml b/pyproject.toml index f5ac09dc7..62b01c67b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -68,6 +68,7 @@ mkdocs-print-site-plugin = "^2.3.6" pytest-cov = "^4.0.0" covdefaults = "^2.3.0" xmldiff = "^2.6.3" +pytest-split-tests = "^1.1.0" [tool.poetry.scripts] ucc-gen="splunk_add_on_ucc_framework.main:main" From feb9bdf27488fcd357e57e47173d72971cf24f35 Mon Sep 17 00:00:00 2001 From: Viktor Tsvetkov <142901247+vtsvetkov-splunk@users.noreply.github.com> Date: Fri, 15 Nov 2024 18:28:03 +0100 Subject: [PATCH 2/2] fix(select): fetching options when some dependency is null (#1463) --- .../SingleInputComponent.test.tsx | 68 ++++++++++++++++++- ui/src/util/api.ts | 12 ++-- 2 files changed, 73 insertions(+), 7 deletions(-) diff --git a/ui/src/components/SingleInputComponent/SingleInputComponent.test.tsx b/ui/src/components/SingleInputComponent/SingleInputComponent.test.tsx index eec9726e6..f4c2b624d 100644 --- a/ui/src/components/SingleInputComponent/SingleInputComponent.test.tsx +++ b/ui/src/components/SingleInputComponent/SingleInputComponent.test.tsx @@ -49,8 +49,8 @@ const renderFeature = (additionalProps?: Partial) => const mockedEntries = [ { name: 'dataApiTest1', content: { testLabel: 'firstLabel', testValue: 'firstValue' } }, { name: 'dataApiTest2', content: { testLabel: 'secondLabel', testValue: 'secondValue' } }, - { name: 'dataApiTest3', content: { testLabel: 'thirdLabel', testValue: 'thirdValue' } }, - { name: 'dataApiTest4', content: { testLabel: 'fourthLabel', testValue: 'fourthValue' } }, + { name: 'true', content: { testLabel: 'thirdLabel', testValue: 'thirdValue' } }, + { name: '0', content: { testLabel: 'fourthLabel', testValue: 'fourthValue' } }, ]; const MOCK_API_URL = '/demo_addon_for_splunk/some_API_endpint_for_select_data'; @@ -167,3 +167,67 @@ it.each([ const { label } = autoCompleteFields[0]; expect(within(inputComponent).getByText(label)).toBeInTheDocument(); }); + +it('should fetch options from API when endpointUrl is provided', async () => { + // server responses with a filtered mockedEntries based on the name parameter + server.use( + http.get(MOCK_API_URL, ({ request }) => { + const url = new URL(request.url); + + const nameParameter = url.searchParams.get('name'); + return HttpResponse.json( + getMockServerResponseForInput( + mockedEntries.filter((entry) => entry.name === nameParameter) + ) + ); + }) + ); + const baseProps = { + ...defaultInputProps, + value: '', + controlOptions: { + createSearchChoice: true, + dependencies: ['name', 'region'], + endpointUrl: MOCK_API_URL, + labelField: 'testLabel', + valueField: 'testValue', + }, + }; + const { rerender } = render(); + + await userEvent.click(screen.getByRole('combobox')); + await screen.findByRole('menuitem', { name: 'No matches' }); + + // undefined value must be omitted + const firstEntry = mockedEntries[0]; + rerender( + + ); + await userEvent.click(screen.getByRole('combobox')); + await screen.findByRole('option', { name: firstEntry.content.testLabel }); + + const secondEntry = mockedEntries[1]; + rerender( + + ); + await userEvent.click(screen.getByRole('combobox')); + await screen.findByRole('option', { name: secondEntry.content.testLabel }); + + const thirdEntry = mockedEntries[2]; + rerender( + + ); + await userEvent.click(screen.getByRole('combobox')); + await screen.findByRole('option', { name: thirdEntry.content.testLabel }); + + const fourthEntry = mockedEntries[3]; + rerender(); + await userEvent.click(screen.getByRole('combobox')); + await screen.findByRole('option', { name: fourthEntry.content.testLabel }); +}); diff --git a/ui/src/util/api.ts b/ui/src/util/api.ts index e44a7657e..b0265eaa9 100755 --- a/ui/src/util/api.ts +++ b/ui/src/util/api.ts @@ -5,9 +5,11 @@ import { generateToast, getUnifiedConfigs } from './util'; import { parseErrorMsg } from './messageUtil'; import { ResponseError } from './ResponseError'; +type ParamsRecord = Record; + export interface RequestParams { endpointUrl: string; - params?: Record; + params?: ParamsRecord; signal?: AbortSignal; body?: BodyInit; handleError: boolean; @@ -21,14 +23,14 @@ export function generateEndPointUrl(name: string) { const DEFAULT_PARAMS = { output_mode: 'json' }; -function createUrl(endpointUrl: string, params: Record): URL { +function createUrl(endpointUrl: string, params: ParamsRecord): URL { const url = new URL( createRESTURL(endpointUrl, { app, owner: 'nobody' }), window.location.origin ); - Object.entries({ ...DEFAULT_PARAMS, ...params }).forEach(([key, value]) => - url.searchParams.append(key, value.toString()) - ); + Object.entries({ ...DEFAULT_PARAMS, ...params }) + .filter(([, value]) => value !== undefined && value !== null) + .forEach(([key, value]) => url.searchParams.append(key, value.toString())); return url; }